“mitao”
2026-03-21 216d50aa9f7d2402dea1ca2087c5f23255916664
Merge remote-tracking branch 'origin/master'
1个文件已删除
6个文件已添加
11个文件已修改
1429 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPoint.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/XpPricingUtil.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpSchedulingDetailServiceImpl.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPricingController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpTestPointManagementController.java 205 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/mapper/XpTestPointMapper.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/XpTestPointService.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPointServiceImpl.java 502 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/XpPricingUtil.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpTestPointMapper.xml 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/AddCruiseMissionJob.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TrajectoryGenerator.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/XpPricingUtil.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java
@@ -262,16 +262,17 @@
        XpOperationsUserVO xpOperationsUserVO = xpOperationsUserService.detailById(id);
        if (xpOperationsUserVO.getAvatar() != null) {
            JSONObject jsonObject = JSONObject.parseObject(xpOperationsUserVO.getAvatar());
            String downloadUrl = null;
            try {
                // 1
                String downloadUrl1 = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                downloadUrl = downloadUrl1;
            } catch (Exception e) {
                e.printStackTrace();
            if(jsonObject!=null){
                String downloadUrl = null;
                try {
                    // 1
                    downloadUrl= aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                jsonObject.put("url", downloadUrl);
                xpOperationsUserVO.setAvatar(jsonObject.toJSONString());
            }
            jsonObject.put("url", downloadUrl);
            xpOperationsUserVO.setAvatar(jsonObject.toJSONString());
        }
        return R.ok(xpOperationsUserVO);
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPoint.java
New file
@@ -0,0 +1,120 @@
package com.xiaopeng.api.model.operation;
import com.baomidou.mybatisplus.annotation.*;
import com.xiaopeng.common.core.web.domain.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
 * <p>
 * 测试demo-点位管理
 * </p>
 *
 * @author mitao
 * @since 2026-02-03
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("xp_test_point")
@ApiModel(value="XpTestPoint对象", description="点位管理")
public class XpTestPoint extends BaseModel {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.NONE)
    private Long id;
    @ApiModelProperty(value = "电子围栏区域id")
    private Long electronicAreaId;
    @TableField(value = "fp_electronic_area_id", updateStrategy = FieldStrategy.NEVER)
    private Long fpElectronicAreaId;
    @ApiModelProperty(value = "点位名称")
    private String pointName;
    @ApiModelProperty(value = "点位poi")
    private String pointPoi;
    @ApiModelProperty(value = "点位编号唯一")
    private String pointNumber;
    @ApiModelProperty(value = "运营状态 1=待启用 2=启用中 3=已停用 4=已失效")
    private Integer operationStatus;
    @ApiModelProperty(value = "点位类型 1=运营点位 2=测试点位")
    private Integer pointType;
    @ApiModelProperty(value = "验证状态 1=待验证、2=验证中、3=已验证 4验证失败 5待生效")
    private Integer verificationStatus;
    @ApiModelProperty(value = "限停时长")
    private Integer parkingTimeLimit;
    @ApiModelProperty(value = "运营类型 1=与运营区同步 2=自定义时间段")
    private Integer operationType;
    @ApiModelProperty(value = "生效周期 1=“每日生效”、2=“仅工作日生效”、3=“仅非工作日生效”、4=“仅节假日生效”")
    private Integer effectivePeriod;
    @ApiModelProperty(value = "生效时间段")
    private String effectiveTimePeriod;
    @ApiModelProperty(value = "点位地址")
    @TableField("point_address")
    private String pointAddress;
    @ApiModelProperty(value = "备注")
    private String remarks;
    @ApiModelProperty(value = "点位照片")
    private String pointPictures;
    @ApiModelProperty(value = "经度")
    private Double pointLon;
    @ApiModelProperty(value = "纬度")
    private Double pointLat;
    @ApiModelProperty(value = "距离 单位米")
    @TableField(exist = false)
    private BigDecimal distance;
    @ApiModelProperty(value = "0否 1是充电点位")
    @TableField("charge_point")
    private Integer chargePoint;
    @ApiModelProperty(value = "0否 1是收车点位")
    @TableField("parking_point")
    private Integer parkingPoint;
    @ApiModelProperty(value = "省份名称")
    @TableField("province_name")
    private String provinceName;
    @ApiModelProperty(value = "省份code")
    @TableField("province_code")
    private String provinceCode;
    @ApiModelProperty(value = "城市名称")
    @TableField("city_name")
    private String cityName;
    @ApiModelProperty(value = "城市code")
    @TableField("city_code")
    private String cityCode;
    @ApiModelProperty(value = "区县名称")
    @TableField("district_name")
    private String districtName;
    @ApiModelProperty(value = "区县code")
    @TableField("district_code")
    private String districtCode;
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -874,6 +874,14 @@
                case ORDER_CANCELLED:
                    //已取消
                    if(!orderId.contains("XU")){
                        //判断订单状态,已经取消的不作处理
                        Object cacheObject = redisService.getCacheObject("ORDER_STATUS:" + orderId);
                        if(null != cacheObject){
                            int order_status = Integer.parseInt(cacheObject.toString());
                            if(0 == order_status){
                                return;
                            }
                        }
                        //行程中取消订单,按照行程结束处理
                        buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence);
                        xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
@@ -904,9 +912,6 @@
    public void buildPushOrderStatus(String orderId, OrderStatusEnum status, Long sequence){
        if(orderId.contains("XU")){
            //巡游单
            //响应消息
            // TODO 1.处理结束当前巡游订单  2.创建新的巡游订单 返航  3.调用xpu车机接口  (判断是返航还是正常  返航需要存储之前的订单id)
            responseMessage(sequence, "");
            //到达目的地
            if(OrderStatusEnum.COMPLETED.equals(status)){
                // 返程找到目前的订单 -》之前的订单 查询生成一个   正常巡游 找到下一个点位   若到达最后点位  则反向找点位  每次判断是否收车状态 是则不进行处理了
@@ -919,6 +924,8 @@
                    xpCruiseOrderClient.completeCruiseOrder(Long.parseLong(orderId.substring(2)));
                    R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(vehicleId);
                    XpVehicle xpVehicle = xpVehicleR.getData();
                    //响应消息
                    responseMessage(sequence, xpVehicle.getVehicleVin());
                    // 运营中 继续执行
                    if(xpVehicle.getOperatingStatus()==1 && xpVehicle.getState()==0){
                        log.info("巡游单到达终点,继续执行下一笔巡游单");
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/XpPricingUtil.java
@@ -89,7 +89,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
@@ -140,8 +140,8 @@
        xpPricingCardVo.setDurationPrice(durationPrice);
        xpPricingCardVo.setTotalPrice(new BigDecimal(startPrice + distancePrice + durationPrice).setScale(2,RoundingMode.HALF_UP).doubleValue());
        // 里程
        xpPricingCardVo.setDistance(realDistance);
        xpPricingCardVo.setDuration(realTime);
        xpPricingCardVo.setDistance(realDistance*1000);
        xpPricingCardVo.setDuration(realTime*60);
        return xpPricingCardVo;
    }
@@ -180,7 +180,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
@@ -361,6 +361,9 @@
                // 时长费
                xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num17")));
                xpPricingCardVo.setDistancePriceNormal(rule.getDouble("num2")*1000);
                xpPricingCardVo.setDurationPriceNormal(rule.getDouble("num3")*60);
            } else {
@@ -423,6 +426,9 @@
                        xpPricingCardVo.setTime(rule.getString("num22"));
                    }
                    xpPricingCardVo.setDistancePriceNormal(rule.getDouble("num2")*1000);
                    xpPricingCardVo.setDurationPriceNormal(rule.getDouble("num3")*60);
                    // 里程
                    xpPricingCardVo.setDistance(realDistance);
@@ -502,6 +508,7 @@
        amount=new BigDecimal(amount).setScale(2,RoundingMode.HALF_UP).doubleValue();
        // 先减去起步价重新计算
        amount = amount - startPrice;
        // 动态计算费用
        startPrice= new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue();
        amount = amount+startPrice;
@@ -510,6 +517,8 @@
        xpPricingCardVo.setDistance(xpPricingCardVo.getDistance()*1000);
        xpPricingCardVo.setDuration(xpPricingCardVo.getDuration()*60);
        return xpPricingCardVo;
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpSchedulingDetailServiceImpl.java
@@ -53,6 +53,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
 * <p>
@@ -489,8 +490,14 @@
            }
        }
        //批量保存排班明细数据
        if (!schedulingDetails.isEmpty()) {
            this.saveOrUpdateBatch(schedulingDetails);
        //找出需要删除的数据
        Set<Long> collect = schedulingDetails.stream().filter(s -> s.getId() != null).collect(Collectors.toList()).stream().map(XpSchedulingDetail::getId).collect(Collectors.toSet());
        List<XpSchedulingDetail> collect1 = list.stream().filter(s -> !collect.contains(s.getId())).collect(Collectors.toList());
        collect1.forEach(s -> s.setDeleted(true));
        collect1.addAll(schedulingDetails);
        if (!collect1.isEmpty()) {
            this.saveOrUpdateBatch(collect1);
        }
        //异步处理消息通知数据
        pushMessage(pushMessage, notifications);
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPricingController.java
@@ -85,7 +85,7 @@
    @GetMapping("/base/v1/mini-program/pricing/rules/{openCityId}")
    @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"));
        XpPricing xpPricing = xpPricingService.getOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, openCityId).last("limit 1"));
        if (xpPricing != null) {
            return R.ok(xpPricing.getPriceRule());
        }
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpTestPointManagementController.java
New file
@@ -0,0 +1,205 @@
package com.xiaopeng.operation.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xiaopeng.api.dto.map.XpPointExportExcelQuery;
import com.xiaopeng.api.dto.operation.PointAddDto;
import com.xiaopeng.api.dto.operation.PointUpdateDto;
import com.xiaopeng.api.dto.operation.XpPointEnableDisableDto;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.model.operation.XpTestPoint;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.controller.BaseController;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.operation.dto.XpPointSpecialDto;
import com.xiaopeng.operation.service.IXpElectronicFenceAreaService;
import com.xiaopeng.operation.service.IXpElectronicFenceService;
import com.xiaopeng.operation.service.XpPointService;
import com.xiaopeng.operation.service.XpTestPointService;
import com.xiaopeng.operation.vo.SpecialPointListVo;
import com.xiaopeng.operation.vo.SpecialPointVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/api/v1/testPoint")
@Api(tags = "测试demo-点位管理")
public class XpTestPointManagementController extends BaseController {
    @Resource
    private XpTestPointService xpTestPointService;
    @Resource
    private IXpElectronicFenceAreaService xpElectronicFenceAreaService;
    @Resource
    private IXpElectronicFenceService xpElectronicFenceService;
    @ApiOperation(value = "获取所有运营中的区域", response = XpElectronicFenceArea.class)
    @PostMapping("/listElectronicFenceArea")
    public R<List<XpElectronicFenceArea>> listElectronicFenceArea() {
        // 获取所有启用的电子围栏
        List<XpElectronicFence> electronicFences = xpElectronicFenceService.lambdaQuery().eq(XpElectronicFence::getStatus, 2).list();
        List<Long> electronicFenceIds = electronicFences.stream().map(XpElectronicFence::getId).collect(Collectors.toList());
        if (electronicFenceIds.isEmpty()) {
            return R.ok(new ArrayList<XpElectronicFenceArea>());
        }
        // 获取电子围栏下启用的运营区域
        List<XpElectronicFenceArea> electronicFenceAreaList = xpElectronicFenceAreaService.lambdaQuery().in(XpElectronicFenceArea::getElectronicId, electronicFenceIds)
                .eq(XpElectronicFenceArea::getAreaStatus, 1).list();
        return R.ok(electronicFenceAreaList);
    }
    @ApiOperation(value = "点位管理列表", response = XpTestPoint.class)
    @PostMapping("/listPoint")
    public R<List<XpTestPoint>> list(@RequestBody PointListQuery query) {
        List<XpTestPoint> pageList = xpTestPointService.listAll(query);
        return R.ok(pageList);
    }
    @ApiOperation(value = "点位管理分页列表", response = XpTestPoint.class)
    @PostMapping("/pageList")
    public R<PageInfo<XpTestPoint>> pageList(@RequestBody PointPageListListQuery query) {
        PageInfo<XpTestPoint> pageList = xpTestPointService.pageList(query);
        return R.ok(pageList);
    }
    @PostMapping("/getByIds")
    public R<List<XpTestPoint>> getByIds(@RequestBody XpPointExportExcelQuery query) {
        List<XpTestPoint> list = xpTestPointService.lambdaQuery().in(XpTestPoint::getId, query.getPointIds()).list();
        return R.ok(list);
    }
    /**
     * 新增点位
     */
    @PostMapping("/addPoint")
    @ResponseBody
    @ApiOperation(value = "新增点位")
    public R add(@Validated @RequestBody PointAddDto pointAddDto) {
        XpTestPoint xpPoint = new XpTestPoint();
        BeanUtils.copyProperties(pointAddDto, xpPoint);
        xpPoint.setFpElectronicAreaId(xpPoint.getElectronicAreaId());
        xpTestPointService.save(xpPoint);
        return R.ok();
    }
    /**
     * 批量删除点位
     */
    @GetMapping("/deletePoint")
    @ResponseBody
    @ApiOperation(value = "删除点位")
    public R deletePoint(@RequestParam("ids") String ids) {
        xpTestPointService.removeBatchByIds(Arrays.stream(ids.split(","))
                .map(Long::parseLong).collect(Collectors.toList()));
        return R.ok();
    }
    /**
     * 编辑点位
     */
    @PostMapping("/editPoint")
    @ApiOperation(value = "编辑点位")
    public R edit(@Validated @RequestBody PointUpdateDto pointAddDto) {
        XpTestPoint xpPoint = new XpTestPoint();
        BeanUtils.copyProperties(pointAddDto, xpPoint);
        xpPoint.setFpElectronicAreaId(null);
        xpTestPointService.updateById(xpPoint);
        return R.ok();
    }
    /**
     * 点位详情
     */
    @GetMapping("/queryPointById")
    @ApiOperation(value = "点位详情")
    public R<XpTestPoint> queryById(@RequestParam Long id) {
        return R.ok(xpTestPointService.getById(id));
    }
    /**
     * 启用/禁用
     */
    @PostMapping("/enableDisablePoint")
    @ApiOperation(value = "启用/禁用")
    public R enableDisable(@RequestBody XpPointEnableDisableDto dto) {
        XpTestPoint xpPoint = xpTestPointService.getById(dto.getId());
        xpPoint.setOperationStatus(dto.getOperationStatus());
        xpPoint.setFpElectronicAreaId(null);
        xpTestPointService.updateById(xpPoint);
        return R.ok();
    }
    /**
     * 设置特殊点位
     */
    @PostMapping("/setSpecialPoint")
    @ApiOperation(value = "设置特殊点位", tags = "后台管理-特殊点位")
    public R setSpecialPoint(@RequestBody XpPointSpecialDto dto) {
        xpTestPointService.update(new LambdaUpdateWrapper<XpTestPoint>().set(XpTestPoint::getChargePoint, 0)
                .set(XpTestPoint::getParkingPoint, 0));
        List<XpTestPoint> list = xpTestPointService.list(new LambdaQueryWrapper<XpTestPoint>()
                .in(XpTestPoint::getId, dto.getChargePoints()));
        list.forEach(e -> {
            e.setChargePoint(1);
            e.setFpElectronicAreaId(null);
        });
        xpTestPointService.updateBatchById(list);
        List<XpTestPoint> list1 = xpTestPointService.list(new LambdaQueryWrapper<XpTestPoint>()
                .in(XpTestPoint::getId, dto.getParkingPoints()));
        list1.forEach(e -> {
            e.setParkingPoint(1);
            e.setFpElectronicAreaId(null);
        });
        xpTestPointService.updateBatchById(list1);
        return R.ok();
    }
    @GetMapping("/listSpecialPoint")
    @ApiOperation(value = "获取特殊点位", tags = "后台管理-特殊点位")
    public R<SpecialPointVo> getSpecialPoint() {
        List<XpTestPoint> chargePoints = xpTestPointService.list(new LambdaQueryWrapper<XpTestPoint>().eq(XpTestPoint::getChargePoint, 1));
        List<XpTestPoint> parkingPoints = xpTestPointService.list(new LambdaQueryWrapper<XpTestPoint>().eq(XpTestPoint::getParkingPoint, 1));
        SpecialPointVo specialPointVo = new SpecialPointVo();
        ArrayList<SpecialPointListVo> chargePointsList = new ArrayList<>();
        for (XpTestPoint chargePoint : chargePoints) {
            SpecialPointListVo specialPointListVo = new SpecialPointListVo();
            specialPointListVo.setPointName(chargePoint.getPointName());
            specialPointListVo.setPointAddress(chargePoint.getPointAddress());
            specialPointListVo.setPointId(chargePoint.getId());
            chargePointsList.add(specialPointListVo);
        }
        specialPointVo.setChargePoints(chargePointsList);
        ArrayList<SpecialPointListVo> parkingPointsList = new ArrayList<>();
        for (XpTestPoint parkingPoint : parkingPoints) {
            SpecialPointListVo specialPointListVo = new SpecialPointListVo();
            specialPointListVo.setPointName(parkingPoint.getPointName());
            specialPointListVo.setPointAddress(parkingPoint.getPointAddress());
            specialPointListVo.setPointId(parkingPoint.getId());
            parkingPointsList.add(specialPointListVo);
        }
        specialPointVo.setParkingPoints(parkingPointsList);
        return R.ok(specialPointVo);
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/mapper/XpTestPointMapper.java
New file
@@ -0,0 +1,35 @@
package com.xiaopeng.operation.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.model.operation.XpPoint;
import com.xiaopeng.api.model.operation.XpTestPoint;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.api.vo.order.XpPointsListVo;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.operation.query.PointByNameQuery;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 * 测试demo-点位管理 Mapper 接口
 * </p>
 *
 * @author liu
 * @author WuGuanFengYue
 * @since 2026-02-03
 */
public interface XpTestPointMapper extends BaseMapper<XpTestPoint> {
    List<XpTestPoint> pointMap(@Param("query") PointMapQuery query);
    List<XpTestPoint> listAll(@Param("query") PointListQuery query);
    List<XpPointsListVo> queryPointByName(@Param("query") PointByNameQuery query);
    List<XpTestPoint> pageList(@Param("pageInfo") PageInfo<XpPoint> pageInfo, @Param("query") PointPageListListQuery query);
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/XpTestPointService.java
New file
@@ -0,0 +1,93 @@
package com.xiaopeng.operation.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
import com.xiaopeng.api.dto.order.HistoryStartPointsDto;
import com.xiaopeng.api.model.operation.XpTestPoint;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
import com.xiaopeng.api.vo.order.XpPointsSearchVo;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.operation.dto.NearestDto;
import com.xiaopeng.operation.query.PointByNameQuery;
import com.xiaopeng.operation.vo.NearestVo;
import com.xiaopeng.operation.vo.OrderDistanceVo;
import javax.validation.Valid;
import java.time.LocalTime;
import java.util.List;
/**
 * <p>
 * 测试demo-点位管理 服务类
 * </p>
 *
 * @author liu
 * @author WuGuanFengYue
 * @since 2026-02-03
 */
public interface XpTestPointService extends IService<XpTestPoint> {
    /**
     * 获取附近上车站点
     */
    NearestVo nearest(@Valid NearestDto dto);
    /**
     * 判断点位是否时间段内
     * @param now
     * @return
     */
    boolean getInTime(LocalTime now,  Integer effectivePeriod, String effectiveTimePeriod);
    List<XpTestPoint> pointMap(PointMapQuery query);
    List<XpTestPoint> listAll(PointListQuery query);
    /**
     * 获取历史上车站点
     * @param historyStartPointsDto
     * @return
     */
    List<XpHistoryStartPointsVo> getHistoryStartPoints(HistoryStartPointsDto historyStartPointsDto);
    /**
     * 获取历史上车站点
     * @param historyEndPointsDto
     * @return
     */
    List<XpHistoryEndPointsVo> getHistoryEndPoints(HistoryEndPointsDto historyEndPointsDto);
    /**
     * 根据名称获取点位列表
     * @param query
     * @return
     */
    XpPointsSearchVo queryPointByName(@Valid PointByNameQuery query);
    /**
     * 获取可下单距离
     * @return
     */
    OrderDistanceVo getOrderDistance();
    PageInfo<XpTestPoint> pageList(PointPageListListQuery query);
    /**
     * 判断点位是否在当前时间范围内有效
     * @param pointId
     * @return
     */
    Boolean nowInTimePoint(Long pointId);
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPointServiceImpl.java
New file
@@ -0,0 +1,502 @@
package com.xiaopeng.operation.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
import com.xiaopeng.api.dto.order.HistoryStartPointsDto;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
import com.xiaopeng.api.vo.order.XpPointsListVo;
import com.xiaopeng.api.vo.order.XpPointsSearchVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.operation.dto.NearestDto;
import com.xiaopeng.operation.mapper.XpSystemSettingMapper;
import com.xiaopeng.operation.mapper.XpTestPointMapper;
import com.xiaopeng.operation.query.PointByNameQuery;
import com.xiaopeng.operation.service.IXpElectronicFenceAreaService;
import com.xiaopeng.operation.service.IXpElectronicFenceService;
import com.xiaopeng.operation.service.XpTestPointService;
import com.xiaopeng.operation.utils.TimeRangeChecker;
import com.xiaopeng.operation.utils.holiday.HolidayUtil;
import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
import com.xiaopeng.operation.vo.NearestNextVo;
import com.xiaopeng.operation.vo.NearestVo;
import com.xiaopeng.operation.vo.OrderDistanceVo;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * 点位管理 服务实现类
 * </p>
 *
 * @author liu
 * @author WuGuanFengYue
 * @since 2026-02-03
 */
@Service
public class XpTestPointServiceImpl extends ServiceImpl<XpTestPointMapper, XpTestPoint> implements XpTestPointService {
    @Resource
    private XpSystemSettingMapper xpSystemSettingMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private HolidayUtil holidayUtil;
    @Resource
    private IXpElectronicFenceAreaService xpElectronicFenceAreaService;
    @Resource
    private IXpElectronicFenceService xpElectronicFenceService;
    @Override
    public NearestVo nearest(NearestDto dto) {
        // 走缓存
        Object orderDistanceObj = redisService.getCacheObject(CacheConstants.NEAR_POINT_DISTANCE);
        Integer orderDistance;
        if (orderDistanceObj != null) {
            orderDistance = Integer.valueOf(orderDistanceObj.toString());
        } else {
            XpSystemSetting xpSystemSetting = xpSystemSettingMapper.selectOne(null);
            orderDistance = xpSystemSetting.getNearPointDistance();
        }
        List<XpTestPoint> list1 = list(new LambdaQueryWrapper<XpTestPoint>().eq(XpTestPoint::getOperationStatus, 2).eq(XpTestPoint::getPointType,1).isNotNull(XpTestPoint::getElectronicAreaId));
        if(list1.size()<2){
            return new NearestVo();
        }
        // 获取所有的站点信息
        List<XpTestPoint> list = list(new LambdaQueryWrapper<XpTestPoint>().eq(XpTestPoint::getOperationStatus, 2).eq(XpTestPoint::getPointType,1).isNotNull(XpTestPoint::getElectronicAreaId)
                // 添加距离计算字段
                .apply("ST_Distance_Sphere(point({0}, {1}), point(point_lon, point_lat)) <= {2}",
                        dto.getLongitude(), dto.getLatitude(), orderDistance));
        list = list.stream().filter(e->e.getElectronicAreaId().equals(dto.getElectronicAreaId())).collect(Collectors.toList());
        NearestVo nearestVo = new NearestVo();
        if(list.isEmpty()){
            nearestVo.setPoints(new ArrayList<>());
            nearestVo.setTotal(0);
            return nearestVo;
        }
        List<NearestNextVo> nearestNextVos = new ArrayList<>();
        LocalTime now = LocalTime.now();
        List<Long> areaIds = list.stream().map(XpTestPoint::getElectronicAreaId).collect(Collectors.toList());
        List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
        List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
        List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
        if (CollUtil.isNotEmpty(fenceIds)) {
            xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
        }
        //判断当前点位是否在运营时间范围内
        for (XpTestPoint xpPoint : list) {
            Integer operationType = xpPoint.getOperationType();
            if(1 == operationType){
                //与运营区同步
                XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPoint.getElectronicAreaId())).findFirst().orElse(null);
                if(null == xpElectronicFenceArea){
                    continue;
                }
                XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null);
                if(null == xpElectronicFence){
                    continue;
                }
                //失效类型 1=永不失效 2=定时失效
                Integer failureType = xpElectronicFence.getFailureType();
                //永不失效,但是还未到开始时间
                if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
                    continue;
                }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
                    //定时失效,但是当前时间不在时间范围内
                    continue;
                }
            }else{
                //自定义时间段
                // 判断是否在时间段内
                boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
                if (!intime) {
                    continue;
                }
            }
            // 计算距离 小于的站点
            double v = FastDistanceCalculator.distanceFast(dto.getLatitude(), dto.getLongitude(), xpPoint.getPointLat(), xpPoint.getPointLon());
            // m做判断
            if ((v) < orderDistance) {
                NearestNextVo nearestNextVo = new NearestNextVo();
                nearestNextVo.setId(xpPoint.getId());
                nearestNextVo.setName(xpPoint.getPointName());
                nearestNextVo.setLatitude(xpPoint.getPointLat());
                nearestNextVo.setLongitude(xpPoint.getPointLon());
                nearestNextVo.setDistance(new BigDecimal(v).setScale(2, RoundingMode.HALF_UP).doubleValue());
                nearestNextVo.setAddress(xpPoint.getPointAddress());
                nearestNextVo.setTime(xpPoint.getParkingTimeLimit());
                nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
                nearestNextVos.add(nearestNextVo);
            }
        }
        if (!nearestNextVos.isEmpty()) {
            nearestNextVos = nearestNextVos.stream().sorted(Comparator.comparing(NearestNextVo::getDistance)).collect(Collectors.toList());
        }
        nearestVo.setPoints(nearestNextVos);
        nearestVo.setTotal(nearestNextVos.size());
        return nearestVo;
    }
    public boolean getInTime(LocalTime now,  Integer effectivePeriod, String effectiveTimePeriod){
        //  2非工作日  0工作日  1节假日 3调休日
        Integer holidayToday = holidayUtil.isHolidayToday();
        if(effectivePeriod==1){
            boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod);
            if (!inTime) {
                return false;
            }
        }else if(effectivePeriod==2){
            if(holidayToday!=0){
                return false;
            }
            boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod);
            if (!inTime) {
                return false;
            }
        }else if(effectivePeriod==3){
            if(holidayToday!=2){
                return false;
            }
            boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod);
            if (!inTime) {
                return false;
            }
        }else if(effectivePeriod==4){
            if(holidayToday!=1){
                return false;
            }
            boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod);
            if (!inTime) {
                return false;
            }
        }
        return true;
    }
    @Override
    public List<XpTestPoint> pointMap(PointMapQuery query) {
        List<XpTestPoint> list = this.baseMapper.pointMap(query);
        return list;
    }
    @Override
    public List<XpTestPoint> listAll(PointListQuery query) {
        if(StringUtils.hasLength(query.getOperationStatus())){
            String[] split = query.getOperationStatus().split(",");
            List<Integer> statusIds = new ArrayList<>();
            for (String s : split) {
                statusIds.add(Integer.valueOf(s));
            }
            query.setOperationStatusIds(statusIds);
        }
        List<XpTestPoint> list = this.baseMapper.listAll(query);
        return list;
    }
    @Override
    public List<XpHistoryStartPointsVo> getHistoryStartPoints(HistoryStartPointsDto historyStartPointsDto) {
        List<XpTestPoint> xpPoints = this.baseMapper.selectBatchIds(historyStartPointsDto.getPointIds());
        ArrayList<XpHistoryStartPointsVo> resultList = new ArrayList<>(10);
        LocalTime now = LocalTime.now();
        List<Long> areaIds = xpPoints.stream().map(XpTestPoint::getElectronicAreaId).collect(Collectors.toList());
        List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
        List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
        List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
        if (CollUtil.isNotEmpty(fenceIds)) {
            xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
        }
        for (XpTestPoint xpPoint : xpPoints) {
            if(xpPoint.getOperationStatus()!=2){
                continue;
            }
            Integer operationType = xpPoint.getOperationType();
            if(1 == operationType){
                //与运营区同步
                XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPoint.getElectronicAreaId())).findFirst().orElse(null);
                if(null == xpElectronicFenceArea){
                    // 不在运营段
                    continue;
                }
                XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null);
                if(null == xpElectronicFence){
                    // 不在运营段
                  continue;
                }
                //失效类型 1=永不失效 2=定时失效
                Integer failureType = xpElectronicFence.getFailureType();
                //永不失效,但是还未到开始时间
                if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
                    continue;
                }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
                    //定时失效,但是当前时间不在时间范围内
                    continue;
                }
            }else{
                //自定义时间段
                // 判断是否在时间段内
                boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
                if (!intime) {
                    // 不在运营段
                 continue;
                }
            }
            XpHistoryStartPointsVo xpHistoryStartPointsVo = new XpHistoryStartPointsVo();
            xpHistoryStartPointsVo.setOperationStatus(1);
            xpHistoryStartPointsVo.setName(xpPoint.getPointName());
            xpHistoryStartPointsVo.setAddress(xpPoint.getPointAddress());
            xpHistoryStartPointsVo.setLatitude(xpPoint.getPointLat());
            xpHistoryStartPointsVo.setLongitude(xpPoint.getPointLon());
            xpHistoryStartPointsVo.setId(xpPoint.getId());
            double distanced = FastDistanceCalculator.distanceFast(historyStartPointsDto.getLat(), historyStartPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon());
            xpHistoryStartPointsVo.setDistance(distanced);
            xpHistoryStartPointsVo.setTime(xpPoint.getParkingTimeLimit());
            xpHistoryStartPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
            resultList.add(xpHistoryStartPointsVo);
        }
        return resultList;
    }
    @Override
    public List<XpHistoryEndPointsVo> getHistoryEndPoints(HistoryEndPointsDto historyEndPointsDto) {
        List<XpTestPoint> xpPoints = this.baseMapper.selectBatchIds(historyEndPointsDto.getPointIds());
        ArrayList<XpHistoryEndPointsVo> resultList = new ArrayList<>(10);
        LocalTime now = LocalTime.now();
        List<Long> areaIds = xpPoints.stream().map(XpTestPoint::getElectronicAreaId).collect(Collectors.toList());
        List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
        List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
        List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
        if (CollUtil.isNotEmpty(fenceIds)) {
            xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
        }
        for (XpTestPoint xpPoint : xpPoints) {
            if(xpPoint.getOperationStatus()!=2){
                continue;
            }
            Integer operationType = xpPoint.getOperationType();
            if(1 == operationType){
                //与运营区同步
                XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPoint.getElectronicAreaId())).findFirst().orElse(null);
                if(null == xpElectronicFenceArea){
                    // 不在运营段
                    continue;
                }
                XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null);
                if(null == xpElectronicFence){
                    // 不在运营段
                    continue;
                }
                //失效类型 1=永不失效 2=定时失效
                Integer failureType = xpElectronicFence.getFailureType();
                //永不失效,但是还未到开始时间
                if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
                    continue;
                }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
                    //定时失效,但是当前时间不在时间范围内
                    continue;
                }
            }else{
                //自定义时间段
                // 判断是否在时间段内
                boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
                if (!intime) {
                    // 不在运营段
                    continue;
                }
            }
            XpHistoryEndPointsVo xpHistoryEndPointsVo = new XpHistoryEndPointsVo();
            xpHistoryEndPointsVo.setOperationStatus(1);
            xpHistoryEndPointsVo.setName(xpPoint.getPointName());
            xpHistoryEndPointsVo.setAddress(xpPoint.getPointAddress());
            xpHistoryEndPointsVo.setLatitude(xpPoint.getPointLat());
            xpHistoryEndPointsVo.setLongitude(xpPoint.getPointLon());
            xpHistoryEndPointsVo.setId(xpPoint.getId());
            double distanced = FastDistanceCalculator.distanceFast(historyEndPointsDto.getLat(), historyEndPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon());
            xpHistoryEndPointsVo.setDistance(distanced);
            xpHistoryEndPointsVo.setTime(xpPoint.getParkingTimeLimit());
            xpHistoryEndPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
            resultList.add(xpHistoryEndPointsVo);
        }
        return resultList;
    }
    @Override
    public XpPointsSearchVo queryPointByName(PointByNameQuery query) {
        XpPointsSearchVo searchVo = new XpTestPointsSearchVo();
        List<XpPointsListVo> list = this.baseMapper.queryPointByName(query);
        if (list.isEmpty()) {
            return searchVo;
        }
        LocalTime now = LocalTime.now();
        List<Long> areaIds = list.stream().map(XpPointsListVo::getElectronicAreaId).collect(Collectors.toList());
        List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
        List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
        List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
        if (CollUtil.isNotEmpty(fenceIds)) {
            xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
        }
        for (XpPointsListVo xpPointsListVo : list) {
            Integer operationType = xpPointsListVo.getOperationType();
            if(1 == operationType){
                //与运营区同步
                XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPointsListVo.getElectronicAreaId())).findFirst().orElse(null);
                if(null == xpElectronicFenceArea){
                    // 不在运营段
                    xpPointsListVo.setState(0);
                }
                XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null);
                if(null == xpElectronicFence){
                    // 不在运营段
                    xpPointsListVo.setState(0);
                }
                //失效类型 1=永不失效 2=定时失效
                Integer failureType = xpElectronicFence.getFailureType();
                //永不失效,但是还未到开始时间
                if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
                    xpPointsListVo.setState(0);
                }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
                    //定时失效,但是当前时间不在时间范围内
                    xpPointsListVo.setState(0);
                }
            }else{
                //自定义时间段
                // 判断是否在时间段内
                boolean intime = getInTime(now, xpPointsListVo.getEffectivePeriod(), xpPointsListVo.getEffectiveTimePeriod());
                if (!intime) {
                    // 不在运营段
                    xpPointsListVo.setState(0);
                }
            }
        }
        // 组装数据 并排序 剔除不在运营段的 数据
        List<XpPointsListVo> resultList = list.stream()
                .peek(vo -> vo.setDistance(BigDecimal.valueOf(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude())).setScale(2, RoundingMode.HALF_UP).doubleValue()))
                .filter(vo -> vo.getState() == 1).collect(Collectors.toList());
        // 可用点位
        List<XpPointsListVo> availablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList());//
        // 不可用点位
        List<XpPointsListVo> unavailablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() == null || !e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList());
        searchVo.setAvailablePoints(availablePoints);
        searchVo.setUnavailablePoints(unavailablePoints);
        return searchVo;
    }
    @Override
    public OrderDistanceVo getOrderDistance() {
        OrderDistanceVo orderDistanceVo = new OrderDistanceVo();
        XpSystemSetting xpSystemSetting = xpSystemSettingMapper.selectOne(null);
        if (xpSystemSetting != null) {
            orderDistanceVo.setMaxDistance(xpSystemSetting.getOrderDistance());
            orderDistanceVo.setMinDistance(xpSystemSetting.getMinOrderDistance());
            orderDistanceVo.setAdsorptionDistance(xpSystemSetting.getAdsorptionDistance());
            orderDistanceVo.setNearPointDistance(xpSystemSetting.getNearPointDistance());
            return orderDistanceVo;
        }
        return orderDistanceVo;
    }
    @Override
    public PageInfo<XpTestPoint> pageList(PointPageListListQuery query) {
        PageInfo<XpTestPoint> pageInfo = new PageInfo<>(query.getPageNum(),query.getPageSize());
        List<XpTestPoint> list = this.baseMapper.pageList(pageInfo,query);
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public Boolean nowInTimePoint(Long pointId) {
        XpTestPoint xpPoint = this.getById(pointId);
        if(null == xpPoint){
            return false;
        }
        Integer operationType = xpPoint.getOperationType();
        if(1 == operationType){
            //与运营区同步
            XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaService.getById(xpPoint.getElectronicAreaId());
            if(null == xpElectronicFenceArea){
                return false;
            }
            XpElectronicFence xpElectronicFence = xpElectronicFenceService.getById(xpElectronicFenceArea.getElectronicId());
            if(null == xpElectronicFence){
                return false;
            }
            //失效类型 1=永不失效 2=定时失效
            Integer failureType = xpElectronicFence.getFailureType();
            //永不失效,但是还未到开始时间
            if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
                return false;
            }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
                //定时失效,但是当前时间不在时间范围内
                return false;
            }
        }else{
            //自定义时间段
            // 判断是否在时间段内
            boolean intime = getInTime(LocalTime.now(), xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
            if (!intime) {
                return false;
            }
        }
        return true;
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/XpPricingUtil.java
@@ -87,7 +87,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
@@ -178,7 +178,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpTestPointMapper.xml
New file
@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopeng.operation.mapper.XpTestPointMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.xiaopeng.api.model.operation.XpTestPoint">
        <id column="id" property="id" />
        <result column="point_name" property="pointName" />
        <result column="point_poi" property="pointPoi" />
        <result column="point_number" property="pointNumber" />
        <result column="operation_status" property="operationStatus" />
        <result column="point_type" property="pointType" />
        <result column="verification_status" property="verificationStatus" />
        <result column="parking_time_limit" property="parkingTimeLimit" />
        <result column="operation_type" property="operationType" />
        <result column="effective_period" property="effectivePeriod" />
        <result column="effective_time_period" property="effectiveTimePeriod" />
        <result column="remarks" property="remarks" />
        <result column="point_pictures" property="pointPictures" />
        <result column="point_lon" property="pointLon" />
        <result column="point_lat" property="pointLat" />
        <result column="is_deleted" property="deleted" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_by" property="createBy" />
        <result column="update_by" property="updateBy" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id,electronic_area_id, point_name, point_poi, point_number, operation_status, point_type, verification_status, parking_time_limit, operation_type, effective_period, effective_time_period, remarks, point_pictures, point_lon, point_lat, is_deleted, create_time, update_time, create_by, update_by
    </sql>
    <select id="pointMap" resultType="com.xiaopeng.api.model.operation.XpTestPoint">
        select t1.*,
        ROUND(
        6378.138 * 2 * ASIN(
        SQRT(
        POW(
        SIN(
        (
        #{query.lat} * PI() / 180 - t1.point_lat * PI() / 180
        ) / 2
        ),
        2
        ) + COS(#{query.lat} * PI() / 180) * COS(t1.point_lat * PI() / 180) * POW(
        SIN(
        (
        #{query.lon} * PI() / 180 - t1.point_lon * PI() / 180
        ) / 2
        ),
        2
        )
        )
        ) * 1000
        ) AS distance
               from xp_test_point t1
        where t1.is_deleted = 0
        <if test="query.pointName != null and query.pointName != ''">
            and t1.point_name like concat('%',#{query.pointName},'%')
        </if>
        <if test="query.pointType != null">
            and t1.point_type = #{query.pointType}
        </if>
        <if test="query.operationStatus != null">
            and t1.operation_status = #{query.operationStatus}
        </if>
        order by distance  asc
    </select>
    <select id="listAll" resultType="com.xiaopeng.api.model.operation.XpTestPoint">
        select t1.*
        from xp_test_point t1
        where t1.is_deleted = 0
        <if test="query.queryParams != null and query.queryParams != ''">
            and (
            t1.point_name like concat('%',#{query.queryParams},'%')
            or t1.point_poi like concat('%',#{query.queryParams},'%')
            or t1.point_number like concat('%',#{query.queryParams},'%')
            )
        </if>
        <if test="query.pointType != null">
            and t1.point_type = #{query.pointType}
        </if>
        <if test="query.cityCode != null and query.cityCode != ''">
            and t1.city_code = #{query.cityCode}
        </if>
        <if test="query.operationStatusIds != null and query.operationStatusIds.size()>0">
            AND t1.operation_status IN
            <foreach collection="query.operationStatusIds" separator="," item="id" open="(" close=")">
                #{id}
            </foreach>
        </if>
        order by t1.create_time desc
    </select>
    <select id="queryPointByName" resultType="com.xiaopeng.api.vo.order.XpPointsListVo">
        select p.id,p.operation_type as operationType ,p.electronic_area_id as electronicAreaId,p.point_name as name,p.point_address as address,p.point_lon as longitude,p.point_lat as latitude,p.effective_period,p.effective_time_period
        from xp_electronic_fence_area xefa
        left join xp_test_point p on p.electronic_area_id = xefa.id
        where p.is_deleted = 0 and p.operation_status =2 and xefa.is_deleted = 0
        and xefa.area_status = 1 and p.electronic_area_id is not null
        and xefa.city_code = #{query.cityCode}
        <if test="query.pointPoi != null and query.pointPoi != ''">
            and ( p.point_address like concat('%',#{query.pointPoi},'%') or p.point_name like concat('%',#{query.pointPoi},'%') )
        </if>
        <if test="query.electronicAreaId != null">
            and p.electronic_area_id = #{query.electronicAreaId}
        </if>
    </select>
    <select id="pageList" resultType="com.xiaopeng.api.model.operation.XpTestPoint">
        select xp.id,xp.point_number as pointNumber,xp.point_name as pointName,xp.point_poi as pointPoi,
               xp.point_address as pointAddress,
               xp.point_lon as pointLon,xp.point_lat as pointLat,xp.create_time as createTime,xp.create_by as createBy
        ,xp.parking_time_limit as parkingTimeLimit,xp.verification_status as verificationStatus,xp.operation_status as operationStatus
        from xp_test_point xp
        where xp.is_deleted = 0
        <if test="query.pointName != null and query.pointName != ''">
            and xp.point_name like concat('%',#{query.pointName},'%')
        </if>
        <if test="query.pointNumber != null and query.pointNumber != ''">
            and xp.point_number like concat('%',#{query.pointNumber},'%')
        </if>
        <if test="query.createBy != null and query.createBy != ''">
            and xp.create_by like concat('%',#{query.createBy},'%')
        </if>
        <if test="query.parkingTimeLimit != null">
            and xp.parking_time_limit = #{query.parkingTimeLimit}
        </if>
        <if test="query.pointLonAndLat != null and query.pointLonAndLat != ''">
            and #{query.pointLonAndLat}  like concat('%',xp.point_lon,'%')
        and #{query.pointLonAndLat}  like concat('%',xp.point_lat,'%')
        </if>
        <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
            and xp.create_time between #{query.startTime} and #{query.endTime}
        </if>
        <if test="query.operationStatusList != null and query.operationStatusList.size() > 0">
            <trim prefix="and (" suffix=")" prefixOverrides="OR">
                <foreach collection="query.operationStatusList" item="st">
                    <choose>
                        <when test="st == 1">OR xp.verification_status = 1</when>
                        <when test="st == 2">OR xp.verification_status = 2</when>
                        <when test="st == 3">OR xp.verification_status = 4</when>
                        <when test="st == 4">OR (xp.verification_status = 3 and xp.operation_status = 1)</when>
                        <when test="st == 5">OR (xp.verification_status = 5 and xp.operation_status = 1)</when>
                        <when test="st == 6">OR xp.operation_status = 2</when>
                        <when test="st == 7">OR xp.operation_status = 3</when>
                        <when test="st == 8">OR xp.operation_status = 4</when>
                        <otherwise>OR 1 = 0</otherwise>
                    </choose>
                </foreach>
            </trim>
        </if>
        order by xp.create_time desc
    </select>
</mapper>
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/AddCruiseMissionJob.java
@@ -41,12 +41,15 @@
            cancelTaxiPassengerVo.setOrderNo(xpOrder.getOrderNumber());
            cancelTaxiPassengerVo.setAppId(appid);
            userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
            log.info("车辆到达终点后的定时任务解绑用户和车辆关系 {}", xpOrder.getOrderNumber());
            // 修改车辆接单状态
            vehicle.setState(0);
            xpVehicleClient.updateVehicleById(vehicle);
            log.info("车辆到达终点后的定时任务回滚车辆状态为空闲 {}", xpOrder.getOrderNumber());
        }
        xpOrderService.addCruiseMission(vehicle, xpOrder);
        log.info("车辆到达终点后的定时任务给车辆派巡游单 {}", xpOrder.getOrderNumber());
    }
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -1260,12 +1260,13 @@
        try {
            redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
        } catch (Exception e) {
            e.printStackTrace();
        }
        //判断还原车辆状态
        if (null == order.getVehicleId()) {
            Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
            if (null != cacheObject1) {
                com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSON.parseObject(cacheObject1.toString());
                JSONObject jsonObject = JSON.parseObject(cacheObject1.toString());
                String vin = jsonObject.getString("vin");
                XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                if (null != vehicle && 0 != vehicle.getState()) {
@@ -1302,21 +1303,6 @@
            Integer i = Integer.valueOf(cacheObject.toString());
            redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, i + 1);
        }
        // 消息推送
//        Map<String, Object> params = new HashMap<>();
//        Map<String, Object> content = new HashMap<>();
//        content.put("orderId", order.getId().toString());
//        content.put("status", OrderStatusEnum.CANCELED.getCode());
//        params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
//        params.put("content", JSONObject.toJSONString(content));
//        params.put("timestamp", new Date().getTime() + "");
//        String message = JSONObject.toJSONString(params);
//        SendMessageDTO sendMessageDTO = new SendMessageDTO();
//        sendMessageDTO.setMessage(message);
//        sendMessageDTO.setAppUserId(uid);
//        xpPushMessageClient.sendStatus(sendMessageDTO);
//        log.info("订单取消消息推送完毕");
        // 移除mongo数据
        xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString());
@@ -1481,6 +1467,9 @@
        if(xpOrder.getStatus() >= 8){
            return R.fail("订单已结束");
        }
        Long appUserId = xpOrder.getAppUserId();
        // 查询车辆
        XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
        switch (status) {
            case 4:
                // 查询起点点位
@@ -1505,6 +1494,8 @@
                LocalDateTime now = LocalDateTime.now();
                xpOrder.setBoardingTime(now);
                xpOrder.setRideTime(now);
                //推送行起点到终点的驶轨迹给乘客端
                sendRoute(appUserId.toString(), orderId, "ORDER_NAVIGATION_END_DATA", xpVehicle.getVehicleVin());
                // 删除定时任务job
                QuartzManager.removeJob((OrderCancelJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ORDER_CANCEL);
                break;
@@ -1515,8 +1506,6 @@
            case 7:
                xpOrder.setGetoffTime(LocalDateTime.now());
                // 解析下车地点
                // 查询车辆
                XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                    GeoJsonPoint point = vehiclePosition.getPoint();
@@ -1582,7 +1571,7 @@
                        endTripJobMaps
                );
                // 添加车辆到达终点后限停时间到后驶离的定时任务
                //时间到后添加巡游订单,解绑车辆关系,车辆驶离点位
                //时间到后将车辆状态回滚到空闲、添加巡游订单,解绑用户和车辆关系,车辆驶离点位
                XpPoint point = xpPointClient.queryById(xpOrder.getEndPointId()).getData();
                Map<String, ? extends Object> jobMaps =
                        new ImmutableMap.Builder<String, String>()
@@ -1627,11 +1616,6 @@
        order.setStatus(8);
        order.setAppUserId(null);
        order.setTripEnd(LocalDateTime.now());
        double exactMinutes = Duration.between(order.getBoardingTime(), order.getTripEnd()).toMillis() / (1000.0 * 60);
        exactMinutes = new BigDecimal(exactMinutes).setScale(2, RoundingMode.HALF_UP).doubleValue();
        order.setDuration(exactMinutes);
        baseMapper.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 8, 24L, TimeUnit.HOURS);
@@ -1678,6 +1662,8 @@
            xpOrderDetail.setOrderId(orderId);
            xpOrderDetail.setType(1);
            xpOrderDetail.setMileage(new BigDecimal(mileageKilometers).setScale(2, RoundingMode.HALF_UP));
            String currentTimeSlot = DateUtils.getCurrentTimeSlot();
            xpOrderDetail.setTime(currentTimeSlot);
            xpOrderDetail.setDuration(duration1);
            xpOrderDetail.setMoney(new BigDecimal(xpPricingCardVo.getStartPrice()).setScale(2, RoundingMode.HALF_UP));
            xpOrderDetails.add(xpOrderDetail);
@@ -1685,7 +1671,6 @@
            xpOrderDetail.setDetailType(2);
            xpOrderDetail.setOrderId(orderId);
            xpOrderDetail.setType(1);
            xpOrderDetail.setMileage(new BigDecimal(mileageKilometers).setScale(2, RoundingMode.HALF_UP));
            xpOrderDetail.setMoney(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2,RoundingMode.HALF_UP));
            xpOrderDetails.add(xpOrderDetail);
            xpOrderDetail = new XpOrderDetail();
@@ -2424,16 +2409,8 @@
    @Override
    public R<FareBreakdownVo> fareBreakdown(Long orderId, String uid) {
        XpOrder order = this.getById(orderId);
        order.setAppUserId(null);
        // 查询订单轨迹
        List<OrderTrajectory> trajectories = mongoTemplate.find(
                new Query(Criteria.where("orderId").is(orderId))
                        .with(Sort.by(Sort.Direction.ASC, "locatetime")),
                OrderTrajectory.class
        );
        FareBreakdownVo res = new FareBreakdownVo();
        res.setChangeMoneyFlag(order.getChangeMoneyFlag());
@@ -2461,22 +2438,6 @@
            }
        }
//        if (order.getDuration() != null && order.getDuration() > 0) {
//            FareBreakdownDetailVo durationDetail = new FareBreakdownDetailVo();
//            durationDetail.setType(order.getDurationType());
//            durationDetail.setDuration(order.getDuration());
//            durationDetail.setMoney(order.getDurationMoney());
//            duration.add(durationDetail);
//        }
//
//        if (order.getLongDistance() != null && order.getLongDistance() > 0) {
//            FareBreakdownDetailVo longDistanceDetail = new FareBreakdownDetailVo();
//            longDistanceDetail.setType(order.getLongDistanceType());
//            longDistanceDetail.setMileage(BigDecimal.valueOf(order.getLongDistance()));
//            longDistanceDetail.setMoney(order.getLongDistancemoney());
//            longDistance.add(longDistanceDetail);
//        }
        res.setStart(start);
        res.setMileage(mileage);
        res.setDuration(duration);
@@ -2492,9 +2453,7 @@
            order.setTripEnd(tripEnd);
            this.updateById(order);
        }
        double exactMinutes = Duration.between(order.getBoardingTime(), order.getTripEnd()).toMillis() / (1000.0 * 60);
        res.setTime(new BigDecimal(exactMinutes).setScale(2, RoundingMode.HALF_UP));
        res.setTime(new BigDecimal(order.getDuration() == null ? 0 : order.getDuration()).multiply(new BigDecimal(60)).setScale(0, RoundingMode.HALF_UP));
        return R.ok(res);
    }
@@ -2573,7 +2532,7 @@
    public void saveVehicleLocation(OrderTrajectory orderTrajectory) {
        // 查询订单信息
        Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId());
        if(status != 6){
        if(status < 6){
            return;
        }
@@ -2585,7 +2544,7 @@
            // 存储mongo数据
            mongoTemplate.save(orderTrajectory);
            // 存储首次定位
            redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation());
            redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation(), 1L, TimeUnit.HOURS);
        } else {
            Map<String, Double> distance = GeodesyUtil.getDistance(orderTrajectory.getLocation(), oldLocation);
            if (null != distance) {
@@ -2595,7 +2554,7 @@
                // 存储mongo数据
                mongoTemplate.save(orderTrajectory);
                // 更新定位
                redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation());
                redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation(), 1L, TimeUnit.HOURS);
            } else {
                log.error("调用高德计算距离出错");
            }
@@ -2788,27 +2747,55 @@
                }
                // 存mongo数据
                xpPricingClient.updateXpGeoQueryEntity(order.getId().toString());
                // 修改车辆信息
                vehicle.setState(1);
                xpVehicleClient.updateVehicleById(vehicle);
                //绑定用户和车辆关系
                addTaxiPassengerVo.setUid(appUserId.toString());
                order.setAppUserId(null);
                this.updateById(order);
                //构建推送消息
                Map<String, Object> params = new HashMap<>();
                Map<String, Object> content = new HashMap<>();
                content.put("orderId", orderId.toString());
                content.put("status", 2);
                params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
                params.put("content", JSONObject.toJSONString(content));
                params.put("timestamp", System.currentTimeMillis() + "");
                String message = JSONObject.toJSONString(params);
                SendMessageDTO dto1 = new SendMessageDTO();
                dto1.setAppUserId(appUserId + "");
                dto1.setMessage(message);
                R<String> stringR = xpPushMessageClient.sendStatus(dto1);
                //推送失败,重试3次
                if(stringR.getCode() != Constants.SUCCESS){
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(dto1);
                            if(stringR1.getCode() == Constants.SUCCESS){
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            log.info("推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(dto), order.getOrderNumber());
                        }
                    });
                }
                redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 2, 24L, TimeUnit.HOURS);
                addTaxiPassengerVo.setOrderNo(order.getOrderNumber());
                // TODO appid
                addTaxiPassengerVo.setAppId(appid);
                userVehicleClient.addTaxiPassenger(addTaxiPassengerVo);
                //推送乘客车辆到达预约点的导航数据
                sendRoute(addTaxiPassengerVo.getUid(), orderId, "ORDER_NAVIGATION_START_DATA", dto.getXpVehicleVin());
            } else {
                //推送行起点到终点的驶轨迹给乘客端
                sendRoute(appUserId.toString(), orderId, "ORDER_NAVIGATION_END_DATA", dto.getXpVehicleVin());
            }
        }
    }
@@ -2900,16 +2887,16 @@
            XpPoint endPoint = xpPointR1.getData();
            xpOrderDetailVO.setEndParkingTimeLimit(endPoint.getParkingTimeLimit());
        }
        // 算时间
        if (xpOrder.getStatus() == 1) {
            R<Integer> r = xpPricingClient.getWaitTime(new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat()));
            if (r.getCode() == R.SUCCESS) {
                xpOrderDetailVO.setEstimatedTime(r.getData());
            } else {
                throw new RuntimeException(r.getMsg());
            }
        }
//        // 算时间
//        if (xpOrder.getStatus() == 1) {
//            R<Integer> r = xpPricingClient.getWaitTime(new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat()));
//            if (r.getCode() == R.SUCCESS) {
//                xpOrderDetailVO.setEstimatedTime(r.getData());
//            } else {
//                throw new RuntimeException(r.getMsg());
//            }
//
//        }
        if (xpOrder.getVehicleId() != null) {
            R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(xpOrder.getVehicleId());
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TrajectoryGenerator.java
File was deleted
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/XpPricingUtil.java
@@ -88,7 +88,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
@@ -179,7 +179,7 @@
                    String timeStr = dynamicPriceObj.toString();
                    // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                    R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId));
                    if(r.getData()==200){
                    if(r.getCode()==200){
                        int num = r.getData();
                        // X单上升一次调价
                        Integer orderNum = getOrderNum(jsonObject, 4);
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -628,7 +628,7 @@
            String jsonString = jsonObject.toJSONString();
            vehicleDetail.setVehiclePictures(jsonString);
        }
        return R.ok();
        return R.ok(vehicleDetail);
    }
    /**
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -248,30 +248,30 @@
        if (Objects.isNull(xpVehicle)) {
            throw new ServiceException("未查询到有效车辆信息", I18nKeyConstant.VEHICLE_NOT_EXISTS);
        }
        // 判断距离是否在范围之内 4米
//        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
//        if (Objects.nonNull(vehiclePosition)) {
//            GeoJsonPoint point = vehiclePosition.getPoint();
//            if(Objects.nonNull(point)){
//                Map<String, Double> distance = GeodesyUtil.getDistance(dto.getLongitude()+ "," + dto.getLatitude(), point.getX()+","+point.getY());
//                if (null != distance) {
//                    Double distance1 = distance.get("WGS84");
//                    if (distance1 > 4) {
//                        throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
//                    }
//                }else {
//                    throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
//                }
//            }else {
//                throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
//            }
//        }
        // 判断距离是否在范围之内 15米
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
        if (Objects.nonNull(vehiclePosition)) {
            GeoJsonPoint point = vehiclePosition.getPoint();
            if(Objects.nonNull(point)){
                Map<String, Double> distance = GeodesyUtil.getDistance(dto.getLongitude()+ "," + dto.getLatitude(), point.getX()+","+point.getY());
                if (null != distance) {
                    Double distance1 = distance.get("WGS84");
                    if (distance1 > 10) {
                        throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
                    }
                }else {
                    throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
                }
            }else {
                throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
            }
        }
        // 车门解锁、后备箱解锁
        VehiclesCommandVo vehiclesCommandVo = new VehiclesCommandVo();
        vehiclesCommandVo.setVin(xpVehicle.getVehicleVin());
        if ("door".equals(dto.getDoorType())) {
            // 开启车门 判断是否为P档
            Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getVehicleVin());
            Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getXpuId());
            if (gearLevel == null || gearLevel != 4) {
                throw new ServiceException("车辆非P档,无法开启车门", I18nKeyConstant.VEHICLE_NOT_P_GEAR);
            }
@@ -286,23 +286,8 @@
            if(xpOrder.getOpenTrunk()==0){
                xpOrder.setOpenTrunk(1);
            }
            if(xpOrder.getOpenTrunk()==1){
            if(xpOrder.getOpenTrunk()==1) {
                xpOrder.setOpenTrunk(2);
                // 添加定时任务
//                xpOrderClient.updateOrderStatus(xpOrder.getId(),7);
//                // 推送倒计时消息 消息推送
//                Map<String, Object> params = new HashMap<>();
//                Map<String, Object> content = new HashMap<>();
//                content.put("orderId", xpOrder.getId().toString());
//                content.put("isOpen", 1);
//                params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc());
//                params.put("content", JSONObject.toJSONString(content));
//                params.put("timestamp", new Date().getTime() + "");
//                String message = JSONObject.toJSONString(params);
//                SendMessageDTO sendMessageDTO = new SendMessageDTO();
//                sendMessageDTO.setMessage(message);
//                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
//                xpPushMessageClient.sendStatus(sendMessageDTO);
            }
        }
        try {