puzhibing
2026-04-20 af5ffb2c572c3188052b0d4b37c4bcec43f11c7d
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -1,49 +1,59 @@
package com.xiaopeng.operation.utils;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
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.pushMessage.SendMessageDTO;
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.operation.XpTradingStrategyClient;
import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient;
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.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpTradingStrategy;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.order.XpOrderReassign;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.OrderType;
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.api.vo.operation.XpTradingStrategyDetailVO;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.constant.Constants;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.operation.config.UidVinBindingConfig;
import com.xiaopeng.operation.dto.PriorityMatchResult;
import com.xiaopeng.operation.mapper.XpElectronicFenceMapper;
import com.xiaopeng.operation.service.IXpElectronicFenceAreaService;
import com.xiaopeng.operation.service.IXpTradingStrategyService;
import com.xiaopeng.operation.service.UidVinPriorityMatcher;
import com.xiaopeng.operation.service.XpPointService;
import com.xiaopeng.operation.utils.mango.VehiclePositionService;
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;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -74,6 +84,9 @@
    private XpCruiseOrderClient xpCruiseOrderClient;
    @Resource
    private XpTradingStrategyClient tradingStrategyClient;
    @Resource
    private XpVehicleClient xpVehicleClient;
    @Resource
@@ -91,9 +104,19 @@
    @Resource
    private XpElectronicFenceMapper xpElectronicFenceMapper;
    @Resource
    private UidVinBindingConfig uidVinBindingConfig;
    @Resource
    private UidVinPriorityMatcher uidVinPriorityMatcher;
    @Resource
    private  XpAppUserCouponClient xpAppUserCouponClient;
    // 自定义线程池
    private static final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(20);
    static {
        threadPoolTaskExecutor.setCorePoolSize(20);
@@ -135,7 +158,6 @@
     * @param firstElement 队列第一个元素
     */
    private void orderProcess(String quoteName, String firstElement) {
        System.out.println("进入处理环节");
        XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null);
        String orderId = firstElement.split("_")[0];
        String lonLat = firstElement.split("_")[1];
@@ -213,13 +235,31 @@
        if (xpOrderR.getCode() == 200) {
            XpOrder xpOrder = xpOrderR.getData();
            if (xpOrder.getStatus() == 1) {
                log.error("五轮推单结束,无车辆接单,执行取消订单 {}", orderNo);
                log.info("五轮推单结束,无车辆接单,执行取消订单 {}", orderNo);
                xpOrderClient.cancelOrder(orderId);
                //推送订单状态给乘客
                SendMessageDTO dto = new SendMessageDTO();
                dto.setAppUserId(xpOrder.getAppUserId().toString());
                dto.setMessage("{\"type\":\"ORDER_STATUS\",\"content\":\"{\\\"orderId\\\":\\\"" + orderId + "\\\",\\\"status\\\":0}\",\"timestamp\":\"" + System.currentTimeMillis() + "\"}");
                xpPushMessageClient.sendStatus(dto);
                R<String> stringR = xpPushMessageClient.sendStatus(dto);
                //推送失败,重试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(dto);
                            if(stringR1.getCode() == Constants.SUCCESS){
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            log.info("五轮推单结束后,无车辆接单,推送取消消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(dto), xpOrder.getOrderNumber());
                        }
                    });
                }
                //将订单从队列中移除
                log.info("五轮推单结束,无车辆接单,执行队列移除订单 {}", orderNo);
                redisService.popFirstElement(quoteName);
@@ -262,6 +302,102 @@
        Long electronicId = xpElectronicFenceAreaService.getById(xpElectronicFenceAreaId).getElectronicId();
        XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(electronicId);
        // ===== 新增:UID-VIN 优先匹配(仅 enabled=true 时生效)=====
        log.info("[人车订单绑定测试] >>>>>> 进入优先匹配判断, uid={}, orderNo={}, 围栏区域ID={}", uid, orderNo, xpElectronicFenceAreaId);
        if (uidVinBindingConfig.isEnabled()) {
            log.info("[人车订单绑定测试] 总开关已开启, 开始执行优先匹配逻辑, uid={}, orderNo={}", uid, orderNo);
            try {
                PriorityMatchResult priorityResult = uidVinPriorityMatcher.tryPriorityMatch(uid, orderNo, String.valueOf(xpElectronicFenceAreaId));
                log.info("[人车订单绑定测试] 优先匹配结果: matched={}, vin={}, failReason={}, uid={}, orderNo={}",
                        priorityResult != null ? priorityResult.isMatched() : "null",
                        priorityResult != null ? priorityResult.getVin() : "null",
                        priorityResult != null ? priorityResult.getFailReason() : "null",
                        uid, orderNo);
                if (priorityResult != null && priorityResult.isMatched()) {
                    String priorityVin = priorityResult.getVin();
                    log.info("[人车订单绑定测试] 匹配成功, 准备获取分布式锁, lockKey=FIND_CAR_{}, orderNo={}", priorityVin, orderNo);
                    RLock priorityLock = redissonClient.getLock("FIND_CAR_" + priorityVin);
                    priorityLock.lock(10, TimeUnit.SECONDS);
                    log.info("[人车订单绑定测试] 分布式锁获取成功, vin={}, orderNo={}", priorityVin, orderNo);
                    try {
                        // 二次校验车辆状态
                        log.info("[人车订单绑定测试] 开始二次校验车辆状态, vin={}, orderNo={}", priorityVin, orderNo);
                        R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(priorityVin);
                        log.info("[人车订单绑定测试] 二次校验-车辆查询结果: code={}, hasData={}, vin={}", vehicleR.getCode(), vehicleR.getData() != null, priorityVin);
                        if (vehicleR.getCode() == 200 && vehicleR.getData() != null) {
                            XpVehicle vehicle = vehicleR.getData();
                            log.info("[人车订单绑定测试] 二次校验-车辆状态: operatingStatus={}, state={}, vehicleType={}, vin={}",
                                    vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType(), priorityVin);
                            if (vehicle.getOperatingStatus() == 1 && vehicle.getState() == 0 && vehicle.getVehicleType() != 1) {
                                log.info("[人车订单绑定测试] 二次校验-车辆状态通过(空闲), 开始校验订单状态, orderNo={}", orderNo);
                                // 二次校验订单状态
                                R<XpOrder> orderCheck = xpOrderClient.queryOrderByOrderNo(orderNo);
                                log.info("[人车订单绑定测试] 二次校验-订单查询结果: code={}, status={}, orderNo={}",
                                        orderCheck.getCode(),
                                        orderCheck.getData() != null ? orderCheck.getData().getStatus() : "null",
                                        orderNo);
                                if (orderCheck.getCode() == 200 && orderCheck.getData() != null && orderCheck.getData().getStatus() == 1) {
                                    log.info("[人车订单绑定测试] 二次校验全部通过, 开始关闭巡游单, vin={}, orderNo={}", priorityVin, orderNo);
                                    // 关闭巡游单
                                    R stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(priorityVin);
                                    log.info("[人车订单绑定测试] 关闭巡游单结果: code={}, vin={}, orderNo={}",
                                            stringR != null ? stringR.getCode() : "null", priorityVin, orderNo);
                                    if (stringR != null && stringR.getCode() == 200) {
                                        log.info("[人车订单绑定测试] 关闭巡游单成功, 开始下发XPU命令, vin={}, orderNo={}", priorityVin, orderNo);
                                        // 下发XPU命令
                                        PushOrderDto pushOrderDto = new PushOrderDto();
                                        pushOrderDto.setVin(priorityVin);
                                        pushOrderDto.setTaskId(orderCheck.getData().getXpuTaskId());
                                        pushOrderDto.setOrderId(orderCheck.getData().getId().toString());
                                        pushOrderDto.setStartLatitude(orderCheck.getData().getStartLat());
                                        pushOrderDto.setStartLongitude(orderCheck.getData().getStartLon());
                                        pushOrderDto.setEndLatitude(orderCheck.getData().getEndLat());
                                        pushOrderDto.setEndLongitude(orderCheck.getData().getEndLon());
                                        pushOrderDto.setEndPoiName(orderCheck.getData().getEndPointName());
                                        pushOrderDto.setOrderType(OrderType.USER_ORDER);
                                        pushOrderDto.setStage(1);
                                        log.info("[人车订单绑定测试] XPU推单参数: vin={}, orderId={}, startLat={}, startLon={}, endLat={}, endLon={}, orderNo={}",
                                                priorityVin, orderCheck.getData().getId(), orderCheck.getData().getStartLat(), orderCheck.getData().getStartLon(),
                                                orderCheck.getData().getEndLat(), orderCheck.getData().getEndLon(), orderNo);
                                        orderMissionClient.pushOrder(pushOrderDto);
                                        log.info("[人车订单绑定测试] ====== 派单成功! uid={}, vin={}, orderNo={}, 从队列移除订单 ======", uid, priorityVin, orderNo);
                                        redisService.removeByPattern(quoteName, orderNo);
                                        return true;
                                    } else {
                                        log.info("[人车订单绑定测试] 关闭巡游单失败, 回退常规流程, vin={}, orderNo={}", priorityVin, orderNo);
                                    }
                                } else {
                                    log.info("[人车订单绑定测试] 二次校验-订单状态不满足(非待派单), 回退常规流程, orderNo={}", orderNo);
                                }
                            } else {
                                if (vehicle.getState() != 0) {
                                    log.info("[人车订单绑定测试] 二次校验-车辆已接单(state={}), 当前有未完成订单, 无法指派, vin={}, plateNumber={}, orderNo={}",
                                            vehicle.getState(), priorityVin, vehicle.getPlateNumber(), orderNo);
                                } else {
                                    log.info("[人车订单绑定测试] 二次校验-车辆状态不满足, 回退常规流程, vin={}, operatingStatus={}, state={}, vehicleType={}",
                                            priorityVin, vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType());
                                }
                            }
                        } else {
                            log.info("[人车订单绑定测试] 二次校验-车辆查询失败, 回退常规流程, vin={}, code={}", priorityVin, vehicleR.getCode());
                        }
                    } catch (Exception e) {
                        log.error("[人车订单绑定测试] 锁内执行异常,回退常规流程, uid={}, vin={}, orderNo={}", uid, priorityVin, orderNo, e);
                    } finally {
                        priorityLock.unlock();
                        log.info("[人车订单绑定测试] 分布式锁已释放, vin={}, orderNo={}", priorityVin, orderNo);
                    }
                } else {
                    log.info("[人车订单绑定测试] 优先匹配未命中, 进入常规流程, uid={}, orderNo={}", uid, orderNo);
                }
            } catch (Exception e) {
                log.error("[人车订单绑定测试] 优先匹配过程异常,回退常规流程, uid={}, orderNo={}", uid, orderNo, e);
            }
        } else {
            log.info("[人车订单绑定测试] 总开关未开启(enabled=false), 跳过优先匹配, uid={}, orderNo={}", uid, orderNo);
        }
        // ===== 新增结束 =====
        for (int i = 0; i < count; i++) {
            //等到sleepTime秒钟
            Thread.sleep(sleepTime * 1000);
@@ -287,7 +423,6 @@
            // 找出符合条件的
            availableVehiclesNearby = availableVehiclesNearby.stream().filter(e -> data.contains(e.getVin())).collect(Collectors.toList());
//            List<VehiclePositionVo> availableVehiclesNearby =vehiclePositionVos.getData();
            if (!availableVehiclesNearby.isEmpty()) {
@@ -350,6 +485,9 @@
                                }
                            }
                            // 距离差
                            if (max1.equals(weightDistanceDifference)) {
                                for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                    RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
@@ -375,6 +513,7 @@
                            }
                            if (max1.equals(weightDistance)) {
                                log.info("车子距离~~");
                                for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                    RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                    LonLatDto lonLatDto = new LonLatDto();
@@ -391,11 +530,22 @@
                                    //  调用地图 获取时间
                                    R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                    if (r.getCode() == 200) {
                                        log.info("车子距离~~{},{},{}",vehiclePosition.getVin(),r.getData().getDistance(),orderNo);
                                        vehiclePosition.setDistance(Double.valueOf(r.getData().getDistance()));
                                    } else {
                                        vehiclePosition.setDistance(0.0);
                                    }
                                }
                                // 分数计算 把时间短的分数调高
                                availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList());
                                double score = 10;
                                for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                    vehiclePosition.setDistance(score);
                                    score--;
                                }
                            }
                            if (max1.equals(weightTime)) {
@@ -420,6 +570,14 @@
                                        vehiclePosition.setSecond(0);
                                    }
                                }
                                // 分数计算 把时间短的分数调高
                                availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList());
                                int score = 10;
                                for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                    vehiclePosition.setSecond(score);
                                    score--;
                                }
                            }
                            if (max1.equals(weightElectricity)) {
@@ -459,6 +617,7 @@
                        // 距离分数
                        if (max.equals(tendencyDistance)) {
                            log.info("车子距离~~");
                            for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                LonLatDto lonLatDto = new LonLatDto();
@@ -476,20 +635,29 @@
                                //  调用地图 获取时间
                                R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                if (r.getCode() == 200) {
                                    log.info("车子距离~~{},{},{}",vehiclePosition.getVin(),r.getData().getDistance(),orderNo);
                                    vehiclePosition.setDistance(Double.valueOf(r.getData().getDistance()));
                                } else {
                                    vehiclePosition.setDistance(0.0);
                                }
                            }
//                            availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList());
//                            int size = tendencyDistance;
//                            // 做比对的分数
//                            double temp = availableVehiclesNearby.get(0).getDistance();
//                            for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
//                                vehiclePosition.setDistanceScore(vehiclePosition.getDistanceScore() + size);
//                                if (temp != vehiclePosition.getDistance()) {
//                                    size--;
//                                }
//                            }
                            // 分数计算 把时间短的分数调高
                            availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList());
                            int size = tendencyDistance;
                            // 做比对的分数
                            double temp = availableVehiclesNearby.get(0).getDistance();
                            int score = 10;
                            for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                vehiclePosition.setDistanceScore(vehiclePosition.getDistanceScore() + size);
                                if (temp != vehiclePosition.getDistance()) {
                                    size--;
                                }
                                vehiclePosition.setDistanceScore(score);
                                score--;
                            }
                        }
@@ -518,16 +686,24 @@
                                    vehiclePosition.setSecond(0);
                                }
                            }
                            // 分数计算 把时间短的分数调高
                            availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList());
                            int size = tendencyTime;
                            // 做比对的分数
                            double temp = availableVehiclesNearby.get(0).getSecond();
                            int score = 10;
                            for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                vehiclePosition.setTimeScore(vehiclePosition.getTimeScore() + size);
                                if (temp != vehiclePosition.getSecond()) {
                                    size--;
                                }
                                vehiclePosition.setTimeScore(score);
                                score--;
                            }
//                            availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList());
//                            int size = tendencyTime;
//                            // 做比对的分数
//                            double temp = availableVehiclesNearby.get(0).getSecond();
//                            for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
//                                vehiclePosition.setTimeScore(vehiclePosition.getTimeScore() + size);
//                                if (temp != vehiclePosition.getSecond()) {
//                                    size--;
//                                }
//                            }
                        }
@@ -799,6 +975,9 @@
                    lock.lock(10, TimeUnit.SECONDS);
                    log.info("队列 {} 车辆 {} 单号 {}", quoteName, vehiclePositionVo.getVin(), orderNo);
                    try {
//                        VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id());
                        R<XpVehicle> vehiclePositionR = xpVehicleClient.findByVehicleVin(vehiclePositionVo.getVin());
                        if (vehiclePositionR.getCode() != 200) {
@@ -810,21 +989,35 @@
                        if (vehiclePosition.getOperatingStatus() != 1 || vehiclePosition.getState() != 0 || vehiclePosition.getVehicleType() == 1) {
                            continue;
                        }
                        // 再次查询一下订单 看是否取消
                        xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo);
                        if (xpOrderR.getCode() != 200) {
                            continue;
                        }
                        xpOrder = xpOrderR.getData();
                        if (xpOrder.getStatus() != 1) {
                            continue;
                        }
                        //  关闭巡游单子
                        R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehiclePosition.getVehicleVin());
                        R stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehiclePosition.getVehicleVin());
                        if (stringR == null || stringR.getCode() != 200) {
                            log.info("关闭巡游单子失败 车牌号 {}", vehiclePosition.getPlateNumber());
                            continue;
                        }
                        log.info("关闭巡游单成功 {} {}", vehiclePosition.getPlateNumber(), orderNo);
                        // 下发命令
                        PushOrderDto pushOrderDto = new PushOrderDto();
                        pushOrderDto.setTaskId(xpOrder.getXpuTaskId());
                        pushOrderDto.setVin(vehiclePosition.getVehicleVin());
                        pushOrderDto.setOrderId(xpOrder.getId().toString());
                        pushOrderDto.setStartLatitude(xpOrder.getStartLat());
                        pushOrderDto.setStartLongitude(xpOrder.getStartLon());
                        pushOrderDto.setEndLatitude(xpOrder.getEndLat());
                        pushOrderDto.setEndLongitude(xpOrder.getEndLon());
                        pushOrderDto.setEndPoiName(xpOrder.getEndPointName());
                        pushOrderDto.setOrderType(OrderType.USER_ORDER);
                        pushOrderDto.setStage(1);
                        // 调用推送服务  orderId + carVin
@@ -855,26 +1048,32 @@
                        }
                        XpVehicle vehicleId1 = vehicleR.getData();
                        log.info("附近只有一个车辆 {} ,直接推单XPU。单号 {}", vehicleId1.getPlateNumber(), orderNo);
                        log.info("当前车辆状态 {} 运营状态 {} 单号 {}", vehicleId1.getOperatingStatus(), vehicleId1.getState(), orderNo);
                        log.info("当前车辆状态 运营状态 {} 单号 {}", vehicleId1.getState(), orderNo);
                        if (vehicleId1.getOperatingStatus() != 1 || vehicleId1.getState() != 0 || vehicleId1.getVehicleType() == 1) {
                            continue;
                        }
                        // 再次查询一下订单 看是否取消
                        xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo);
                        if (xpOrderR.getCode() != 200) {
                            continue;
                        }
                        xpOrder = xpOrderR.getData();
                        if (xpOrder.getStatus() != 1) {
                            continue;
                        }
                        //  关闭巡游单子
                        R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehicleId1.getVehicleVin());
                        R<?> stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehicleId1.getVehicleVin());
                        if (stringR == null || stringR.getCode() != 200) {
                            log.info("关闭巡游单子失败 车牌号 {}", vehicleId1.getPlateNumber());
                            continue;
                        }
                        PushOrderDto pushOrderDto = new PushOrderDto();
                        log.info("关闭巡游单成功 {} {}", vehicleId1.getPlateNumber(), orderNo);
                        PushOrderDto pushOrderDto = buildPushOrderDto(xpOrder);
                        pushOrderDto.setVin(vehiclePosition.getVin());
                        pushOrderDto.setOrderId(xpOrder.getId().toString());
                        pushOrderDto.setStartLatitude(xpOrder.getStartLat());
                        pushOrderDto.setStartLongitude(xpOrder.getStartLon());
                        pushOrderDto.setEndLatitude(xpOrder.getEndLat());
                        pushOrderDto.setEndLongitude(xpOrder.getEndLon());
                        pushOrderDto.setOrderType(OrderType.USER_ORDER);
                        pushOrderDto.setStage(1);
                        pushOrderDto.setTaskId(xpOrder.getXpuTaskId());
                        // 调用推送服务  orderId + carVin
                        orderMissionClient.pushOrder(pushOrderDto);
                        log.info("开始推送 {} 订单到XPU", xpOrder.getOrderNumber());
@@ -889,41 +1088,228 @@
                }
            }
            log.info("没有找到空闲车辆 {},尝试连环派单给即将服务结束的车辆", orderNo);
            // 查询状态为1的车辆vin
            R<List<String>> servingVehicles = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(xpElectronicFence.getId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount(),1));
            if (servingVehicles.getCode() != 200) {
                continue;
            }
            LonLatDto userPostion = new LonLatDto(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
            XpTradingStrategyDetailVO strategyDetailVO = tradingStrategyClient.queryById().getData();
            Integer distanceRegardAsEnding = strategyDetailVO.getDistanceRegardAsEnding();
            Integer timeRegardAsEnding = strategyDetailVO.getTimeRegardAsEnding();
            Integer backupPower = strategyDetailVO.getBackupPower();
            Integer destToPassenger = strategyDetailVO.getDestToPassenger();
            Integer endingTimeToUseTime = strategyDetailVO.getEndingTimeToUseTime();
            LocalDateTime rideTime = xpOrder.getRideTime();
            LocalDateTime now = LocalDateTime.now();
            Optional<XpOrder> luckyOrderOpt = servingVehicles.getData().stream()
                    //获取位置
                    .map(vin -> mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class))
                    .map(VehiclePosition::getOrderId)
                    .map(xpOrderClient::queryOrderById)
                    .filter(R::isSuccess)
                    .map(R::getData)
                    .filter(o -> {
                        XpVehicle xpVehicle = xpVehicleClient.queryById(o.getVehicleId()).getData();
                        Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(o.getAppUserId().toString()));
                        RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class);
                        if (routeRemain.getDuration() / 60 > timeRegardAsEnding) {
                            return false;
                        }
                        if (routeRemain.getDistance() > distanceRegardAsEnding) {
                            return false;
                        }
                        if (routeRemain.getDuration() / 60 > timeRegardAsEnding) {
                            return false;
                        }
                        RouteAndFareDto next = new RouteAndFareDto();
                        next.setOrigin(new LonLatDto(o.getStartLon(),o.getStartLat()));
                        next.setDestination(new LonLatDto(o.getEndLon(),o.getEndLat()));
                        RouteVo route = xpMapClient.getDistanceAndDuration(next).getData();
                        if (route.getDistance() > backupPower + xpVehicle.getMileageRange())
                            return false;
                        return routeRemain.getDistance() < destToPassenger
                                || now.plusSeconds(routeRemain.getDuration())
                                .plusMinutes(endingTimeToUseTime)
                                .isBefore(rideTime);
                    })
                    .findAny();
            if (luckyOrderOpt.isPresent()) {
                XpOrder luckyOder = luckyOrderOpt.get();
                log.info("有空闲车辆 {} 订单 {}", luckyOder.getOrderNumber(), orderNo);
                XpVehicle xpVehicle = xpVehicleClient.queryById(luckyOder.getVehicleId()).getData();
                // 设置路线信息
                RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                routeAndFareDto.setDestination(userPostion);
                routeAndFareDto.setOrigin(new LonLatDto(luckyOder.getEndLon(),luckyOder.getEndLat()));
                RouteVo routeToOrigin = xpMapClient.getDistanceAndDuration(routeAndFareDto).getData();
                Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(luckyOder.getAppUserId().toString()));
                RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class);
                routeToOrigin.getPolyline().addAll(0, routeRemain.getPolyline());
                routeToOrigin.setDuration(routeToOrigin.getDuration() + routeRemain.getDuration());
                routeToOrigin.setDistance(routeToOrigin.getDistance() + routeRemain.getDistance());
                PushOrderDto pushOrderDto = buildPushOrderDto(xpOrder);
                pushOrderDto.setVin(xpVehicle.getVehicleVin());
                pushOrderDto.setTaskId(xpOrder.getXpuTaskId());
                // 订单流转
                orderMissionClient.pushOrder(pushOrderDto);
                redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), xpOrder.getId());
                redisService.setCacheObject(CacheConstants.navigationStart(xpOrder.getAppUserId().toString()), routeToOrigin);
                redisService.removeByPattern(quoteName,xpOrder.getOrderNumber());
                log.info("将订单 {} 从队列 {} 弹出去", orderNo, quoteName);
                break;
            }
        }
        return false;
    }
    private static PushOrderDto buildPushOrderDto(XpOrder xpOrder) {
        PushOrderDto pushOrderDto = new PushOrderDto();
        pushOrderDto.setOrderId(xpOrder.getId().toString());
        pushOrderDto.setStartLatitude(xpOrder.getStartLat());
        pushOrderDto.setStartLongitude(xpOrder.getStartLon());
        pushOrderDto.setEndLatitude(xpOrder.getEndLat());
        pushOrderDto.setEndLongitude(xpOrder.getEndLon());
        pushOrderDto.setEndPoiName(xpOrder.getEndPointName());
        pushOrderDto.setOrderType(OrderType.USER_ORDER);
        pushOrderDto.setStage(1);
        return pushOrderDto;
    }
    private boolean isClose(XpOrder xpOrder,RouteAndFareDto routeAndFareDto) {
        LonLatDto lonLatDto = new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat());
        routeAndFareDto.setOrigin(lonLatDto);
        return xpMapClient.getDistanceAndDuration(routeAndFareDto).getData().getDistance() < 800;
    }
    @Resource
    private MongoTemplate mongoTemplate;
    /**
     * 订单处理
     * 重新改派
     * 1.优化好点 做个倒计时的异步改派多次
     * @param count 轮数
     * @param uid
     * @param uid 用户id
     * @param longitude  经度
     * @param latitude  纬度
     * @param orderNo 订单号
     */
    @SneakyThrows
    public void reassignPushOrder(int count, String uid, Double longitude, Double latitude, String orderNo) {
        System.out.println("进入推单环环节");
    public XpOrderReassign reassignPushOrder(int count, String uid, Double longitude, Double latitude, String orderNo) {
        log.info("进入推单环环节");
        if (count == 0) {
            count = 1;
        }
        // 订单状态
        R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo);
        if (xpOrderR.getCode() != 200) {
            return;
            return null;
        }
//        List<Integer> notDrive = new ArrayList<Integer>(){{ //未行驶的情况下订单故障状态点 status=2、3、4、5
//            add(OrderStatusEnum.READY_DEPART.getCode());add(OrderStatusEnum.PICK_UP.getCode());
//            add(OrderStatusEnum.PICK_UP_GUESTS.getCode());add(OrderStatusEnum.PASSENGER_BOARDED.getCode());
//        }};
        if (xpOrderR.getData().getStatus() != 1) {
            return;
            return null;
        }
        XpOrder data = xpOrderR.getData();
        XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null);
        XpOrderReassign entity = new XpOrderReassign(data.getId(),data.getVehicleId(),data.getFleetId(),longitude,latitude,"接驾故障");
        entity.setIsComplete(false);
        entity.setAppUserId(Long.valueOf(uid));
        //循环找车
        for (int i = 0; i < count; i++) {
            log.info("进入找车环节");
            List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(longitude, latitude, xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount());
            // 获取车辆的区域信息
            if (positionList.isEmpty()) {
                continue;
                log.info("没有找到空闲车辆 {},尝试连环派单给即将服务结束的车辆", orderNo);
                // 查询状态为1的车辆vin
                Set<String> vinList = positionList.stream().map(VehiclePosition::getVin).collect(Collectors.toSet());
                R<List<String>> servingVehicles = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(data.getFleetId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount(),1));
                if (servingVehicles.getCode() != 200) {
                    continue;
                }
                LonLatDto userPosition = new LonLatDto(data.getStartLon(), data.getStartLat());//人的位置
                XpTradingStrategyDetailVO strategyDetailVO = tradingStrategyClient.queryById().getData();
                Integer distanceRegardAsEnding = strategyDetailVO.getDistanceRegardAsEnding();
                Integer timeRegardAsEnding = strategyDetailVO.getTimeRegardAsEnding();
                Integer backupPower = strategyDetailVO.getBackupPower();
                Integer destToPassenger = strategyDetailVO.getDestToPassenger();
                Integer endingTimeToUseTime = strategyDetailVO.getEndingTimeToUseTime();
                LocalDateTime rideTime = data.getRideTime();
                LocalDateTime now = LocalDateTime.now();
                Optional<XpOrder> luckyOrderOpt = servingVehicles.getData().stream()
                        //获取位置
                        .map(vin -> mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class))
                        .map(VehiclePosition::getOrderId)
                        .map(xpOrderClient::queryOrderById)
                        .filter(R::isSuccess)
                        .map(R::getData)
                        .filter(o -> {
                            XpVehicle xpVehicle = xpVehicleClient.queryById(o.getVehicleId()).getData();
                            Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(o.getAppUserId().toString()));
                            RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class);
                            if (routeRemain.getDuration() / 60 > timeRegardAsEnding) {
                                return false;
                            }
                            if (routeRemain.getDistance() > distanceRegardAsEnding) {
                                return false;
                            }
                            if (routeRemain.getDuration() / 60 > timeRegardAsEnding) {
                                return false;
                            }
                            RouteAndFareDto next = new RouteAndFareDto();
                            next.setOrigin(new LonLatDto(o.getStartLon(),o.getStartLat()));
                            next.setDestination(new LonLatDto(o.getEndLon(),o.getEndLat()));
                            RouteVo route = xpMapClient.getDistanceAndDuration(next).getData();
                            if (route.getDistance() > backupPower + xpVehicle.getMileageRange())
                                return false;
                            return routeRemain.getDistance() < destToPassenger
                                    || now.plusSeconds(routeRemain.getDuration())
                                    .plusMinutes(endingTimeToUseTime)
                                    .isBefore(rideTime);
                        })
                        .findAny();
                if (luckyOrderOpt.isPresent()) {
                    XpOrder luckyOder = luckyOrderOpt.get();
                    log.info("有空闲车辆 {} 订单 {}", luckyOder.getOrderNumber(), orderNo);
                    XpVehicle xpVehicle = xpVehicleClient.queryById(luckyOder.getVehicleId()).getData();
                    // 设置路线信息
                    RouteAndFareDto pickUpRoute = new RouteAndFareDto();
                    pickUpRoute.setDestination(userPosition);
                    pickUpRoute.setOrigin(new LonLatDto(luckyOder.getEndLon(),luckyOder.getEndLat()));
                    RouteVo routeToOrigin = xpMapClient.getDistanceAndDuration(pickUpRoute).getData();
                    Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(luckyOder.getAppUserId().toString()));
                    RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class);
                    routeToOrigin.getPolyline().addAll(0, routeRemain.getPolyline());
                    routeToOrigin.setDuration(routeToOrigin.getDuration() + routeRemain.getDuration());
                    routeToOrigin.setDistance(routeToOrigin.getDistance() + routeRemain.getDistance());
                    PushOrderDto pushOrderDto = buildPushOrderDto(data);
                    pushOrderDto.setVin(xpVehicle.getVehicleVin());
                    // 订单流转
                    orderMissionClient.pushOrder(pushOrderDto);
                    redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), data.getId());
                    redisService.setCacheObject(CacheConstants.navigationStart(data.getAppUserId().toString()), routeToOrigin);
                    break;
                }
            }
            // 直接派单  定义一个锁来锁定车辆
@@ -944,30 +1330,43 @@
                    continue;
                }
                //  关闭巡游单子
                R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehicleId1.getVehicleVin());
                R<?> stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehicleId1.getVehicleVin());
                if (stringR == null || stringR.getData() == null) {
                    log.info("关闭巡游单子失败");
                    continue;
                }
                PushOrderDto pushOrderDto = new PushOrderDto();
                pushOrderDto.setTaskId(data.getXpuTaskId());
                pushOrderDto.setVin(vehiclePosition.getVin());
                pushOrderDto.setOrderId(data.getId().toString());
                pushOrderDto.setStartLatitude(data.getStartLat());
                pushOrderDto.setStartLongitude(data.getStartLon());
                pushOrderDto.setEndLatitude(data.getEndLat());
                pushOrderDto.setEndLongitude(data.getEndLon());
                pushOrderDto.setEndPoiName(data.getEndPointName());
                pushOrderDto.setOrderType(OrderType.USER_ORDER);
                pushOrderDto.setStage(1);
                // 调用推送服务  orderId + carVin
                orderMissionClient.pushOrder(pushOrderDto);
            } catch (Exception e) {
                entity.setNewVehicleId(vehicleId1.getId());
                entity.setNewFleetId(vehicleId1.getFleetId());
                entity.setIsComplete(true);
//                //接单成功 将 修改 订单的状态=1 ( 状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成)
//                orderCarStatus = true;
                xpOrderClient.updateOrderStatus(data.getId(), OrderStatusEnum.PENDING_ORDER.getCode(), false);
                redisService.setCacheObject("ORDER_STATUS:" + data.getId(), OrderStatusEnum.PENDING_ORDER.getCode(), 24L, TimeUnit.HOURS);
                break;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        //保存改派记录
        return entity;
    }