puzhibing
2026-04-11 b6f3de8451867d85242b2bd706fcfa4a65df4ff7
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -15,6 +15,8 @@
import com.xiaopeng.api.dto.account.UcUserInfo;
import com.xiaopeng.api.dto.account.UseUserCouponDto;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO;
import com.xiaopeng.api.dto.map.OrderRouteAndFareDto;
import com.xiaopeng.api.dto.operation.CruisePointDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.order.GetOrderNumDto;
@@ -27,19 +29,19 @@
import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO;
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.automaticPilot.VehicleBuriedPointClient;
import com.xiaopeng.api.feignClient.maintenance.XpTaskRuleClient;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.operation.XpCruisePlanClient;
import com.xiaopeng.api.feignClient.operation.XpPointClient;
import com.xiaopeng.api.feignClient.operation.XpPricingClient;
import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.*;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.model.order.*;
@@ -54,8 +56,10 @@
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.constant.Constants;
import com.xiaopeng.common.core.constant.HttpStatus;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.CancelOrderSceneEnum;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
import com.xiaopeng.common.core.exception.ServiceException;
@@ -84,10 +88,8 @@
import com.xiaopeng.order.model.query.XpOrderExcelQuery;
import com.xiaopeng.order.model.query.XpOrderPageQuery;
import com.xiaopeng.order.model.vo.*;
import com.xiaopeng.order.service.IXpOrderCancelService;
import com.xiaopeng.order.service.IXpOrderEvaluateService;
import com.xiaopeng.order.service.IXpOrderReassignService;
import com.xiaopeng.order.service.IXpOrderService;
import com.xiaopeng.order.service.*;
import com.xiaopeng.order.utils.GDMapGeocodingUtil;
import com.xiaopeng.order.utils.TaxiPricingDemoService;
import com.xiaopeng.order.utils.RegionCodeFilterUtil;
import com.xiaopeng.order.utils.XpPricingUtil;
@@ -103,17 +105,21 @@
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -130,6 +136,9 @@
@Service
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class XpOrderServiceImpl extends ServiceImpl<XpOrderMapper, XpOrder> implements IXpOrderService {
    private static final String REASSIGN_CANCEL_CONTEXT_PREFIX = "REASSIGN_CANCEL_CONTEXT:";
    private static final long REASSIGN_CANCEL_CONTEXT_TTL_MINUTES = 5L;
    private final UserResourcesClient userResourcesClient;
    private final XpPointClient xpPointClient;
@@ -152,6 +161,10 @@
    private final XpTaskRuleClient xpTaskRuleClient;
    private final XpCruisePlanClient xpCruisePlanClient;
    private final XpPricingUtil xpPricingUtil;
    private final GDMapGeocodingUtil gdMapGeocodingUtil;
    private final VehicleBuriedPointClient vehicleBuriedPointClient;
    private final IXpTestOrderService xpTestOrderService;
    private final XpMapClient xpMapClient;
    @Autowired
@@ -581,6 +594,8 @@
        vo.setEndAddress(order.getEndAddress());
        vo.setOrderMoney(order.getOrderMoney());
        vo.setStatus(order.getStatus());
        vo.setStartPointName(order.getStartPointName());
        vo.setEndPointName(order.getEndPointName());
        // 用户信息
        if (Objects.nonNull(order.getAppUserId()) && userInfoMap != null && userInfoMap.containsKey(order.getAppUserId().toString())) {
@@ -618,8 +633,11 @@
                String vin = jsonObject.getString("vin");
                XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                if (null != vehicle && 0 != vehicle.getState()) {
                    vehicle.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle);
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(vehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("管理后台取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                }
            }
        }
@@ -629,6 +647,7 @@
            order.setStatus(0);
            order.setAppUserId(null);
            baseMapper.updateById(order);
            redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
            // 消息推送
            Map<String, Object> params = new HashMap<>();
            Map<String, Object> content = new HashMap<>();
@@ -641,12 +660,33 @@
            SendMessageDTO sendMessageDTO = new SendMessageDTO();
            sendMessageDTO.setMessage(message);
            sendMessageDTO.setAppUserId(String.valueOf(userId));
            xpPushMessageClient.sendStatus(sendMessageDTO);
            R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
            //推送失败,重试3次
            if(stringR.getCode() != Constants.SUCCESS){
                ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                executor.execute(() -> {
                    for (int i = 0; i < 3; i++) {
                        R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                        if(stringR1.getCode() == Constants.SUCCESS){
                            break;
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        log.info("运维人员取消订单推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), order.getOrderNumber());
                    }
                });
            }
            return;
        }
        // 1. 更新订单状态为已取消(0)
        lambdaUpdate().set(XpOrder::getStatus, 0)
                .eq(XpOrder::getId, order.getId()).update();
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        // 2. 保存取消记录
        XpOrderCancel orderCancel = new XpOrderCancel();
@@ -667,7 +707,25 @@
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setMessage(message);
        sendMessageDTO.setAppUserId(String.valueOf(userId));
        xpPushMessageClient.sendStatus(sendMessageDTO);
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("运维人员取消订单推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), order.getOrderNumber());
                }
            });
        }
        log.info("运营人员取消订单成功,推送乘客消息完成");
        //查询车辆信息
@@ -688,8 +746,11 @@
            //还原车辆状态
            if(1 == xpVehicle.getState()){
                xpVehicle.setState(0);
                xpVehicleClient.updateVehicleById(xpVehicle);
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(xpVehicle.getId());
                vehicle1.setState(0);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("管理后台取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
            }
            // 下发命令
@@ -700,7 +761,7 @@
            orderMissionClient.cancelOrder(pushOrderDto);
            log.info("运营人员取消订单成功,开始执行巡游订单 {}", order.getId());
            //车辆继续巡游
            addCruiseMission(xpVehicle);
            addCruiseMission(xpVehicle.getId());
        } else {
            log.info("查询车辆信息失败,订单ID: {}, 下发取消订单命令失败", order.getId());
@@ -712,27 +773,151 @@
     * 关闭订单
     */
    private void closeOrder(XpOrder order) {
        // 更新订单状态为已完成(8)
        this.lambdaUpdate().set(XpOrder::getStatus, 7)
                .eq(XpOrder::getId, order.getId()).update();
        XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
        order.setStatus(7);
        order.setGetoffTime(LocalDateTime.now());
        // 解析下车地点
        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)){
                double x = point.getX();
                double y = point.getY();
                Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
                order.setGetoffAddress(geocode.get("address"));
            }
        }
        //计算行驶总距离和时长
        List<OrderTrajectory> orderTrajectoryList = mongoTemplate.find(new Query().addCriteria(Criteria.where("orderId").is(order.getId())), OrderTrajectory.class);
        Double reduce = orderTrajectoryList.stream().map(OrderTrajectory::getDistance).reduce(0.0, Double::sum);
        order.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue());
        long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - order.getTripBegin().toEpochSecond(ZoneOffset.of("+8"));
        order.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue());
        Long appUserId = order.getAppUserId();
        order.setAppUserId(null);
        this.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 7, 24L, TimeUnit.HOURS);
        //结束行程
        endTrip(order.getId(), order.getAppUserId().toString());
        // 消息推送
        Map<String, Object> params1 = new HashMap<>();
        Map<String, Object> content1 = new HashMap<>();
        content1.put("orderId", order.getId().toString());
        content1.put("status", OrderStatusEnum.SEE_OFF_GUESTS.getCode());
        params1.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
        params1.put("content", JSON.toJSONString(content1));
        params1.put("timestamp", new Date().getTime() + "");
        String message1 = JSON.toJSONString(params1);
        SendMessageDTO sendMessageDTO1 = new SendMessageDTO();
        sendMessageDTO1.setMessage(message1);
        sendMessageDTO1.setAppUserId(appUserId.toString());
        R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO1);
        //推送失败,重试3次
        if(stringR1.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> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO1);
                    if(stringR2.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("运维人员关闭订单推送订单状态消息失败:{} {} {}", stringR2.getMsg(), JSON.toJSONString(sendMessageDTO1), order.getOrderNumber());
                }
            });
        }
        // 推送倒计时消息
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
        content.put("orderId", order.getId().toString());
        content.put("status", OrderStatusEnum.APPROVAL_REJECTION.getCode());
        params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
        params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content));
        content.put("isOpen", 1);
        params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc());
        params.put("content", JSON.toJSONString(content));
        params.put("timestamp", new Date().getTime() + "");
        String message = JSONObject.toJSONString(params);
        String message = JSON.toJSONString(params);
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setMessage(message);
        sendMessageDTO.setAppUserId(String.valueOf(order.getAppUserId()));
        xpPushMessageClient.sendStatus(sendMessageDTO);
        log.info("运营人员取消订单成功,推送乘客消息完成");
        log.info("订单关闭成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
        sendMessageDTO.setAppUserId(appUserId.toString());
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR2.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("推送倒计时消息失败:{} {} {}", stringR2.getMsg(), JSON.toJSONString(sendMessageDTO), order.getOrderNumber());
                }
            });
        }
        //给XPU推送订单取消的报文
        PushOrderDto pushOrderDto = new PushOrderDto();
        pushOrderDto.setOrderId(order.getId().toString());
        pushOrderDto.setVin(xpVehicle.getVehicleVin());
        pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
        orderMissionClient.cancelOrder(pushOrderDto);
        //结束行程,修改状态和计算费用
        endTrip(order.getId(), appUserId.toString());
        // 消息推送
        Map<String, Object> params2 = new HashMap<>();
        Map<String, Object> content2 = new HashMap<>();
        content2.put("orderId", order.getId().toString());
        content2.put("status", OrderStatusEnum.APPROVAL_REJECTION.getCode());
        params2.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
        params2.put("content", JSON.toJSONString(content2));
        params2.put("timestamp", new Date().getTime() + "");
        String message2 = JSON.toJSONString(params2);
        SendMessageDTO sendMessageDTO2 = new SendMessageDTO();
        sendMessageDTO2.setMessage(message2);
        sendMessageDTO2.setAppUserId(appUserId.toString());
        R<String> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO2);
        //推送失败,重试3次
        if(stringR2.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> stringR3 = xpPushMessageClient.sendStatus(sendMessageDTO2);
                    if(stringR3.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("运维人员关闭订单推送订单状态消息失败:{} {} {}", stringR3.getMsg(), JSON.toJSONString(sendMessageDTO1), order.getOrderNumber());
                }
            });
        }
        //创建定时任务执行延迟驶离终点和下发巡游单
        XpPoint point = xpPointClient.queryById(order.getEndPointId()).getData();
        Map<String, ? extends Object> jobMaps =
                new ImmutableMap.Builder<String, String>()
                        .put("id", order.getId().toString())
                        .put("appid", appid)
                        .build();
        QuartzManager.addJob(
                AddCruiseMissionJob.class,
                (AddCruiseMissionJob.name + order.getId()).toUpperCase(),
                TimeJobType.ADD_CRUISE_MISSION,
                DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                jobMaps
        );
    }
    /**
@@ -766,23 +951,6 @@
        }
        XpVehicle newVehicle = vehicleResult.getData().get(0);
        // 5. 校验新车辆的运营状态
        // 车辆状态:1=待完善 2=待运营 3=保险/年检过期
        // 运营状态:1=运营中 2=维修中 3=已收车 4=车辆异常
        // 当前模式:1=接单 2=测试
        // 模式状态:1=开始接单/开始测试 2=停止接单/停止测试
        if (Objects.isNull(newVehicle.getStatus()) || newVehicle.getStatus() == 3) {
            throw new ServiceException("新车辆保险或年检已过期,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_STATUS_INVALID);
        }
        if (Objects.isNull(newVehicle.getOperatingStatus()) || newVehicle.getOperatingStatus() != 1) {
            throw new ServiceException("新车辆运营状态异常,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_OPERATING_STATUS_INVALID);
        }
        if (Objects.isNull(newVehicle.getAcceptOrTest()) || newVehicle.getAcceptOrTest() != 1) {
            throw new ServiceException("新车辆当前不在接单模式", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_IN_ACCEPT_MODE);
        }
        if (Objects.isNull(newVehicle.getAcceptOrTestStatus()) || newVehicle.getAcceptOrTestStatus() != 1) {
            throw new ServiceException("新车辆未开始接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_START_ACCEPT);
        }
        if (Objects.isNull(newVehicle.getState()) || newVehicle.getState() != 0) {
            throw new ServiceException("新车辆已接单,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_FREE);
        }
@@ -800,11 +968,16 @@
                    // 6.1.1 取消原订单指令
                    PushOrderDto cancelDto = new PushOrderDto();
                    cancelDto.setTaskId(IdUtil.getSnowflakeNextIdStr());
                    cancelDto.setOrderId(order.getId().toString());
                    cancelDto.setVin(oldVehicle.getVehicleVin());
                    cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
                    cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
                    orderMissionClient.cancelOrder(cancelDto);
                    log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}", orderId, oldVehicle.getVehicleVin());
                    cacheReassignCancelContext(orderId, oldVehicleId, newVehicleId,
                            oldVehicle.getVehicleVin(), currentStatus);
                    log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}, taskId: {}, cancelScene: {}",
                            orderId, oldVehicle.getVehicleVin(), cancelDto.getTaskId(), cancelDto.getCancelScene());
                    // 6.1.2 解绑乘客与原车辆关系
                    if (Objects.nonNull(order.getAppUserId())) {
@@ -818,12 +991,15 @@
                    }
                    // 6.1.3 修改原车辆状态为空闲
                    oldVehicle.setState(0);
                    xpVehicleClient.updateVehicleById(oldVehicle);
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(oldVehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("管理后台改派订单,车辆状态修改0 {}", oldVehicle.getPlateNumber());
                    log.info("已将原车辆状态设为空闲,车辆ID: {}", oldVehicleId);
                    // 6.1.4 为原车辆创建返程巡游订单
                    createReturnCruiseOrder(oldVehicle, order);
                    createReturnCruiseOrder(oldVehicle.getId(), order);
                } else {
                    log.warn("查询原车辆信息失败,车辆ID: {}", oldVehicleId);
                }
@@ -866,6 +1042,8 @@
        if (Objects.nonNull(newFleetId)) {
            order.setFleetId(newFleetId);
        }
        //重置订单状态为【待接单】
        order.setStatus(1);
        this.updateById(order);
        // 10. 保存改派记录
@@ -916,14 +1094,46 @@
            log.info("已下发订单到新车辆,订单ID: {}, VIN: {}", orderId, newVehicle.getVehicleVin());
            // 11.3 更新新车辆状态为已接单
            newVehicle.setState(1);
            xpVehicleClient.updateVehicleById(newVehicle);
            XpVehicle vehicle1 = new XpVehicle();
            vehicle1.setId(newVehicle.getId());
            vehicle1.setState(1);
            xpVehicleClient.updateVehicleById(vehicle1);
            log.info("管理后台改派订单,车辆状态修改1 {}", newVehicle.getPlateNumber());
            log.info("已将新车辆状态设为已接单,车辆ID: {}", newVehicleId);
            //12.向小程序用户推送订单改派通知
            Map<String, Object> params = new HashMap<>();
            Map<String, Object> content = new HashMap<>();
            content.put("orderId", order.getId().toString());
            content.put("status", order.getStatus());
            params.put("type", PushMessageTypeEnum.ORDER_REASSIGN.getDesc());
            params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content));
            params.put("timestamp", new Date().getTime() + "");
            String message = JSONObject.toJSONString(params);
            SendMessageDTO sendMessageDTO = new SendMessageDTO();
            sendMessageDTO.setMessage(message);
            sendMessageDTO.setAppUserId(String.valueOf(order.getAppUserId()));
            xpPushMessageClient.sendStatus(sendMessageDTO);
        } catch (Exception e) {
            log.error("处理新车辆失败,车辆ID: {},错误: {}", newVehicleId, e.getMessage());
        }
    }
    private void cacheReassignCancelContext(Long orderId, Long oldVehicleId, Long newVehicleId,
                                            String oldVehicleVin, Integer preReassignStatus) {
        JSONObject context = new JSONObject();
        context.put("orderId", orderId);
        context.put("oldVehicleId", oldVehicleId);
        context.put("newVehicleId", newVehicleId);
        context.put("oldVehicleVin", oldVehicleVin);
        context.put("cancelScene", CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
        context.put("operationTime", System.currentTimeMillis());
        context.put("preReassignStatus", preReassignStatus);
        redisService.setCacheObject(REASSIGN_CANCEL_CONTEXT_PREFIX + orderId, context.toJSONString(),
                REASSIGN_CANCEL_CONTEXT_TTL_MINUTES, TimeUnit.MINUTES);
        log.info("记录改派取消上下文成功,orderId: {}, oldVehicleId: {}, newVehicleId: {}, preReassignStatus: {}",
                orderId, oldVehicleId, newVehicleId, preReassignStatus);
    }
    /**
@@ -935,10 +1145,10 @@
     * - 其他状态,默认返回原出发点
     * </p>
     *
     * @param oldVehicle 原车辆信息
     * @param order      当前订单信息
     */
    private void createReturnCruiseOrder(XpVehicle oldVehicle, XpOrder order) {
    private void createReturnCruiseOrder(Long vehicleId, XpOrder order) {
        XpVehicle oldVehicle = xpVehicleClient.queryById(vehicleId).getData();
        try {
            // 查询该车辆最新的一条巡游订单
            XpCruiseOrder lastCruise = xpCruiseOrderMapper.selectOne(
@@ -1198,17 +1408,21 @@
        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()) {
                    vehicle.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle);
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(vehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("用户取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                }
            }
        }
@@ -1217,11 +1431,13 @@
            order.setStatus(0);
            order.setAppUserId(null);
            baseMapper.updateById(order);
            redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
            return;
        }
        order.setStatus(0);
        order.setAppUserId(null);
        baseMapper.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        XpOrderCancel xpOrderCancel = new XpOrderCancel();
        xpOrderCancel.setOrderId(orderId);
        xpOrderCancel.setUserId(Long.valueOf(uid));
@@ -1229,30 +1445,6 @@
        xpOrderCancel.setCancelReason("用户取消订单");
        xpOrderCancelService.save(xpOrderCancel);
        // 设置当天的取消次数缓存
        Object cacheObject = redisService.getCacheObject("CANCEL_ORDER_" + uid);
        if (cacheObject == null) {
            redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, 1);
        } else {
            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());
@@ -1279,8 +1471,11 @@
            //还原车辆状态
            if (1 == xpVehicle.getState()) {
                xpVehicle.setState(0);
                xpVehicleClient.updateVehicleById(xpVehicle);
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(xpVehicle.getId());
                vehicle1.setState(0);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("用户取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
            }
            //下发XPU报文
@@ -1291,7 +1486,7 @@
            orderMissionClient.cancelOrder(pushOrderDto);
            log.info("用户取消订单成功,开始执行巡游订单 {}", order.getId());
            //车辆继续巡游
            addCruiseMission(xpVehicle);
            addCruiseMission(xpVehicle.getId());
        }
    }
@@ -1308,6 +1503,7 @@
        order.setStatus(0);
        order.setAppUserId(null);
        baseMapper.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        XpOrderCancel xpOrderCancel = new XpOrderCancel();
        xpOrderCancel.setOrderId(Long.valueOf(orderId));
        xpOrderCancel.setUserId(1l);
@@ -1330,19 +1526,31 @@
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setMessage(message);
        sendMessageDTO.setAppUserId(String.valueOf(appUserId));
        xpPushMessageClient.sendStatus(sendMessageDTO);
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("定时任务取消订单推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), order.getOrderNumber());
                }
            });
        }
        log.info("定时任务取消订单推送消息完毕");
        // 移除mongo数据
        xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString());
        // 设置当天的取消次数缓存
        Object cacheObject = redisService.getCacheObject("CANCEL_ORDER_" + appUserId);
        if (cacheObject == null) {
            redisService.setCacheCancelOrder("CANCEL_ORDER_" + appUserId, 1);
        } else {
            Integer i = Integer.valueOf(cacheObject.toString());
            redisService.setCacheCancelOrder("CANCEL_ORDER_" + appUserId, i + 1);
        }
        return order;
    }
@@ -1369,6 +1577,7 @@
        xpOrder.setAppUserId(null);
        xpOrder.setStatus(10);
        baseMapper.updateById(xpOrder);
        redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), 10, 24L, TimeUnit.HOURS);
        XpOrderEvaluate evaluate = new XpOrderEvaluate();
        evaluate.setOrderId(xpOrder.getId());
@@ -1395,6 +1604,9 @@
        if(xpOrder.getStatus() >= 8){
            return R.fail("订单已结束");
        }
        Long appUserId = xpOrder.getAppUserId();
        // 查询车辆
        XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
        switch (status) {
            case 4:
                // 查询起点点位
@@ -1416,44 +1628,39 @@
                xpOrder.setArrivalTime(LocalDateTime.now());
                break;
            case 5:
                xpOrder.setBoardingTime(LocalDateTime.now());
                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;
            case 6:
                // 行程开始时间
                xpOrder.setTripBegin(LocalDateTime.now());
                redisService.deleteObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId());
                break;
            case 7:
                Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData();
                // 添加自动结束行程定时任务job
                Map<String, ? extends Object> endTripJobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .build();
                QuartzManager.addJob(
                        EndTripJob.class,
                        (EndTripJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.END_TRIP,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)),
                        endTripJobMaps
                );
                // 添加车辆到达终点后限停时间到后驶离的定时任务
                //时间到后添加巡游订单,解绑车辆关系,车辆驶离点位
                XpPoint point = xpPointClient.queryById(xpOrder.getEndPointId()).getData();
                Map<String, ? extends Object> jobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .build();
                QuartzManager.addJob(
                        AddCruiseMissionJob.class,
                        (AddCruiseMissionJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.ADD_CRUISE_MISSION,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                        jobMaps
                );
                xpOrder.setGetoffTime(LocalDateTime.now());
                // 解析下车地点
                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)){
                        double x = point.getX();
                        double y = point.getY();
                        Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
                        xpOrder.setGetoffAddress(geocode.get("address"));
                    }
                }
                //计算行驶总距离和时长
                List<OrderTrajectory> orderTrajectoryList = mongoTemplate.find(new Query().addCriteria(Criteria.where("orderId").is(xpOrder.getId())), OrderTrajectory.class);
                Double reduce = orderTrajectoryList.stream().map(OrderTrajectory::getDistance).reduce(0.0, Double::sum);
                xpOrder.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue());
                long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - xpOrder.getTripBegin().toEpochSecond(ZoneOffset.of("+8"));
                xpOrder.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue());
                // 推送倒计时消息
                Map<String, Object> params = new HashMap<>();
                Map<String, Object> content = new HashMap<>();
@@ -1466,12 +1673,64 @@
                SendMessageDTO sendMessageDTO = new SendMessageDTO();
                sendMessageDTO.setMessage(message);
                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
                xpPushMessageClient.sendStatus(sendMessageDTO);
                R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
                //推送失败,重试3次
                if(stringR.getCode() != Constants.SUCCESS){
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                            if(stringR1.getCode() == Constants.SUCCESS){
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            log.info("推送倒计时消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), xpOrder.getOrderNumber());
                        }
                    });
                }
                //创建定时结束订单和等待结束后下发巡游单的定时任务
                Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData();
                // 添加自动结束行程定时任务job
                Map<String, ? extends Object> endTripJobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .put("orderType", OrderType.USER_ORDER)
                                .build();
                QuartzManager.addJob(
                        EndTripJob.class,
                        (EndTripJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.END_TRIP,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)),
                        endTripJobMaps
                );
                // 添加车辆到达终点后限停时间到后驶离的定时任务
                //时间到后将车辆状态回滚到空闲、添加巡游订单,解绑用户和车辆关系,车辆驶离点位
                XpPoint point = xpPointClient.queryById(xpOrder.getEndPointId()).getData();
                Map<String, ? extends Object> jobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .put("orderType", OrderType.USER_ORDER)
                                .build();
                QuartzManager.addJob(
                        AddCruiseMissionJob.class,
                        (AddCruiseMissionJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.ADD_CRUISE_MISSION,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                        jobMaps
                );
                break;
        }
        xpOrder.setStatus(status);
        xpOrder.setAppUserId(null);
        this.updateById(xpOrder);
        redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
        return R.ok();
    }
@@ -1497,12 +1756,8 @@
        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);
        // 根据订单所属开通城市id 查询定价
        R<XpPricing> pricingByCityId = xpPricingClient.getPricingByCid(order.getCityId());
@@ -1547,6 +1802,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);
@@ -1554,7 +1811,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();
@@ -1877,11 +2133,11 @@
    /**
     * 添加巡游任务下发命令
     *
     * @param vehicle
     * @param order
     */
    public void addCruiseMission(XpVehicle vehicle, XpOrder order) {
    public void addCruiseMission(Long vehicleId, XpOrder order) {
        XpVehicle vehicle = xpVehicleClient.queryById(vehicleId).getData();
        log.info("添加巡游订单 {}", vehicle.getPlateNumber());
        if (vehicle.getState() != 0 || vehicle.getOperatingStatus() != 1) {
            log.info("添加巡游单失败,车辆状态限制 {}", vehicle.getState());
@@ -1958,14 +2214,18 @@
        if(null != xpTaskRule){
            LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime();
            if (vehicleCollectionTime.isBefore(LocalTime.now())) {
                vehicle.setOperatingStatus(3);
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(vehicle.getId());
                vehicle1.setOperatingStatus(3);
                xpVehicleClient.updateVehicleById(vehicle1);
                //找到车辆的收车点位 更新终点点位
                R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder);
                xpCruiseOrder = returnCruisePoint.getData();
                xpCruiseOrder.setOrderType(2);
                xpCruiseOrder.setOrderReverse(1);
                if(200 != returnCruisePoint.getCode()){
                    xpCruiseOrder = returnCruisePoint.getData();
                    xpCruiseOrder.setOrderType(2);
                    xpCruiseOrder.setOrderReverse(1);
                }
            }
            xpVehicleClient.updateVehicleById(vehicle);
        }
        xpCruiseOrderMapper.insert(xpCruiseOrder);
        log.info("添加巡游单成功 {}", xpCruiseOrder.getId());
@@ -1986,9 +2246,10 @@
    /**
     * 取消订单后的继续巡游任务
     * @param vehicle
     * @param vehicleId
     */
    public void addCruiseMission(XpVehicle vehicle) {
    public void addCruiseMission(Long vehicleId) {
        XpVehicle vehicle = xpVehicleClient.queryById(vehicleId).getData();
        if (vehicle.getState() != 0 || vehicle.getOperatingStatus() != 1) {
            return;
        }
@@ -2067,14 +2328,18 @@
        if(null != xpTaskRule){
            LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime();
            if (vehicleCollectionTime.isBefore(LocalTime.now())) {
                vehicle.setOperatingStatus(3);
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(vehicle.getId());
                vehicle1.setOperatingStatus(3);
                xpVehicleClient.updateVehicleById(vehicle1);
                //找到车辆的收车点位 更新终点点位
                R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder);
                xpCruiseOrder = returnCruisePoint.getData();
                xpCruiseOrder.setOrderType(2);
                xpCruiseOrder.setOrderReverse(1);
                if(200 != returnCruisePoint.getCode()){
                    xpCruiseOrder = returnCruisePoint.getData();
                    xpCruiseOrder.setOrderType(2);
                    xpCruiseOrder.setOrderReverse(1);
                }
            }
            xpVehicleClient.updateVehicleById(vehicle);
        }
        xpCruiseOrderMapper.insert(xpCruiseOrder);
@@ -2293,16 +2558,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());
@@ -2330,22 +2587,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);
@@ -2361,9 +2602,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);
    }
@@ -2391,6 +2630,7 @@
        }
        baseMapper.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 9, 24L, TimeUnit.HOURS);
        return R.ok();
    }
@@ -2430,38 +2670,40 @@
    }
    @Override
    public Integer countActiveOrdersByCityId(Long cityId) {
        Long num = this.baseMapper.selectCount(new LambdaQueryWrapper<XpOrder>()
                .eq(XpOrder::getCityId, cityId)
                .eq(XpOrder::getStatus, 1));
        return num.intValue();
    }
    @Override
    public void saveVehicleLocation(OrderTrajectory orderTrajectory) {
        // 查询订单信息
        XpOrder xpOrder = this.getById(orderTrajectory.getOrderId());
        Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId());
        if(status < 6 || status > 8){
            return;
        }
        // 计算距离
        // 获取上一次定位
        String oldLocation = redisService.getCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId());
        if (StringUtils.isEmpty(oldLocation)) {
            // 首次定位
            xpOrder.setMileageKilometers(0D);
            xpOrder.setAppUserId(null);
            this.updateById(xpOrder);
            orderTrajectory.setDistance(0D);
            // 存储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) {
                Double distance1 = distance.get("WGS84");
                if (distance1 > 50 && xpOrder.getStatus() == 6) {//大于50米表示在移动,且在服务中的时候记录里程
                    xpOrder.setMileageKilometers(BigDecimal.valueOf(xpOrder.getMileageKilometers()).add(new BigDecimal(distance1).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN)).doubleValue());
                    xpOrder.setAppUserId(null);
                    this.updateById(xpOrder);
                    // 存储本次距离
                    orderTrajectory.setDistance(distance1);
                    // 存储mongo数据
                    mongoTemplate.save(orderTrajectory);
                    // 更新定位
                    redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation());
                }
                // 存储本次距离
                orderTrajectory.setDistance(distance1);
                // 存储mongo数据
                mongoTemplate.save(orderTrajectory);
                // 更新定位
                redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation(), 1L, TimeUnit.HOURS);
            } else {
                log.error("调用高德计算距离出错");
            }
@@ -2625,6 +2867,29 @@
                xpCruiseOrder.setVehicleId(null);
                xpCruiseOrderMapper.updateById(xpCruiseOrder);
                log.info("修改巡游单状态,开始执行巡游单 {}", dto.getOrderId());
                // 封装埋点消息实体
                VehicleEventDTO vehicleEventDTO = new VehicleEventDTO();
                vehicleEventDTO.setVin(dto.getXpVehicleVin());
                vehicleEventDTO.setXpuId("");
                vehicleEventDTO.setOrderId(String.valueOf(dto.getOrderId()));
                vehicleEventDTO.setEventKey("RT_xpu_vehicle_trace_upload");
                vehicleEventDTO.setEventTime(System.currentTimeMillis());
                Map<String,Object> attributes = new HashMap<>();
                attributes.put("vin",vehicleEventDTO.getVin());
                attributes.put("order_id",vehicleEventDTO.getOrderId());
                attributes.put("order_type","cruise_order");
                attributes.put("timestamp",vehicleEventDTO.getEventTime());
                attributes.put("current_main_status",OrderStatus.ORDER_STARTED);
                attributes.put("current_sub_status","");
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(dto.getXpVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                    attributes.put("odometer_km",vehiclePosition.getTotalOdometer());
                }else {
                    attributes.put("odometer_km","");
                }
                vehicleEventDTO.setAttributes(attributes);
                vehicleBuriedPointClient.sendVehicleEvent(vehicleEventDTO);
                log.info("巡游单埋点消息,开始执行推送: {}", dto.getOrderId());
            }
        }
        //乘客单处理逻辑
@@ -2654,26 +2919,160 @@
                }
                // 存mongo数据
                xpPricingClient.updateXpGeoQueryEntity(order.getId().toString());
                // 修改车辆信息
                vehicle.setState(1);
                xpVehicleClient.updateVehicleById(vehicle);
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(vehicle.getId());
                vehicle1.setState(1);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("推单成功后的处理逻辑,车辆状态修改1 {}", vehicle.getPlateNumber());
                //绑定用户和车辆关系
                addTaxiPassengerVo.setUid(appUserId.toString());
                order.setAppUserId(null);
                this.updateById(order);
                redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 2, 24L, TimeUnit.HOURS);
                //构建推送消息
                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);
                //生成前往上车点的导航数据
                //查询车辆位置
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(dto.getXpVehicleVin())), VehiclePosition.class);
                if (Objects.isNull(vehiclePosition)) {
                    throw new RuntimeException("车辆位置信息不存在");
                }
                LonLatDto destination = new LonLatDto();
                LonLatDto origin = new LonLatDto();
                //查询司机当前位置到起点的线路
                origin.setLongitude(vehiclePosition.getPoint().getX());
                origin.setLatitude(vehiclePosition.getPoint().getY());
                destination.setLongitude(order.getStartLon());
                destination.setLatitude(order.getStartLat());
                OrderRouteAndFareDto dto2 = new OrderRouteAndFareDto();
                dto2.setOrderId(orderId);
                dto2.setOrigin(origin);
                dto2.setDestination(destination);
                dto2.setRouteType(1);
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto2);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                //缓存数据,用于后续推给乘客导航线路
                redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + appUserId, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
                //推送乘客车辆到达预约点的导航数据
                sendRoute(addTaxiPassengerVo.getUid(), orderId, "ORDER_NAVIGATION_START_DATA", dto.getXpVehicleVin());
            } else {
                //推送行起点到终点的驶轨迹给乘客端
                sendRoute(appUserId.toString(), orderId, "ORDER_NAVIGATION_END_DATA", dto.getXpVehicleVin());
            }
            if(order.getStatus() == 2){
                // 封装埋点消息实体
                VehicleEventDTO vehicleEventDTO = new VehicleEventDTO();
                vehicleEventDTO.setVin(dto.getXpVehicleVin());
                vehicleEventDTO.setXpuId("");
                vehicleEventDTO.setOrderId(String.valueOf(dto.getOrderId()));
                vehicleEventDTO.setEventKey("RT_xpu_vehicle_trace_upload");
                vehicleEventDTO.setEventTime(System.currentTimeMillis());
                Map<String,Object> attributes = new HashMap<>();
                attributes.put("vin",vehicleEventDTO.getVin());
                attributes.put("order_id",vehicleEventDTO.getOrderId());
                attributes.put("order_type","user_order");
                attributes.put("timestamp",vehicleEventDTO.getEventTime());
                attributes.put("current_main_status",OrderStatus.ORDER_EN_ROUTE_TO_PICKUP);
                attributes.put("current_sub_status","");
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(dto.getXpVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                    attributes.put("odometer_km",vehiclePosition.getTotalOdometer());
                }else {
                    attributes.put("odometer_km","");
                }
                vehicleEventDTO.setAttributes(attributes);
                vehicleBuriedPointClient.sendVehicleEvent(vehicleEventDTO);
                log.info("用户单埋点消息,开始执行推送: {}", dto.getOrderId());
            }
        }
        //测试订单
        if (OrderType.TEST_ORDER.equals(orderType)) {
            XpTestOrder xpTestOrder = xpTestOrderService.getById(orderId);
            //订单为待接单状态
            if (xpTestOrder.getStatus() < 4) {
                xpTestOrder.setAcceptanceTime(LocalDateTime.now());
                R<XpVehicle> byVehicleVin = xpVehicleClient.findByVehicleVin(dto.getXpVehicleVin());
                XpVehicle vehicle = null;
                if (byVehicleVin.getCode() == 200) {
                    vehicle = byVehicleVin.getData();
                    xpTestOrder.setVehicleId(vehicle.getId());
                    xpTestOrder.setFleetId(vehicle.getFleetId());
                }
                xpTestOrder.setStatus(2);
                // 修改车辆信息
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(vehicle.getId());
                vehicle1.setState(1);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("推单成功后的处理逻辑,车辆状态修改1 {}", vehicle.getPlateNumber());
                xpTestOrder.setStartTestPointId(null);
                xpTestOrderService.updateById(xpTestOrder);
                redisService.setCacheObject("TEST_ORDER_STATUS:" + xpTestOrder.getId(), 2, 24L, TimeUnit.HOURS);
            }
        }
        if (OrderType.TEST_CRUISE_ORDER.equals(orderType)) {
            XpTestOrder xpTestOrder = xpTestOrderService.getById(orderId);
            //订单为待接单状态
            if (xpTestOrder.getStatus() < 4) {
                xpTestOrder.setAcceptanceTime(LocalDateTime.now());
                R<XpVehicle> byVehicleVin = xpVehicleClient.findByVehicleVin(dto.getXpVehicleVin());
                XpVehicle vehicle = null;
                if (byVehicleVin.getCode() == 200) {
                    vehicle = byVehicleVin.getData();
                    xpTestOrder.setVehicleId(vehicle.getId());
                    xpTestOrder.setFleetId(vehicle.getFleetId());
                }
                xpTestOrder.setStatus(6);
                xpTestOrder.setStartTestPointId(null);
                xpTestOrderService.updateById(xpTestOrder);
                redisService.setCacheObject("TEST_ORDER_STATUS:" + xpTestOrder.getId(), 6, 24L, TimeUnit.HOURS);
            }
        }
    }
@@ -2715,8 +3114,26 @@
            SendMessageDTO messageDTO = new SendMessageDTO();
            messageDTO.setAppUserId(appUserId);
            messageDTO.setMessage(jsonObject.toJSONString());
            System.err.println(messageDTO);
            xpPushMessageClient.sendRoute(messageDTO);
            R<String> stringR = xpPushMessageClient.sendRoute(messageDTO);
            XpOrder xpOrder = this.getById(orderId);
            //推送失败,重试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(messageDTO);
                        if(stringR1.getCode() == Constants.SUCCESS){
                            break;
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        log.info("推送乘客端导航数据消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(messageDTO), xpOrder.getOrderNumber());
                    }
                });
            }
        }
    }
@@ -2747,16 +3164,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());
@@ -2764,7 +3181,14 @@
            xpOrderDetailVO.setPlateNumber(vehicle.getPlateNumber());
            xpOrderDetailVO.setVehiclePictures(vehicle.getVehiclePictures());
        }
        Integer status = xpOrder.getStatus();
        if(status == 4 || status == 7 || status == 8){
            Boolean data = xpVehicleClient.getVehicleTrunkOpenStatus(xpOrder.getAppUserId(), xpOrder.getVehicleId()).getData();
            xpOrder.setOpenTrunk(data ? 1 : 2);
            xpOrderDetailVO.setOpenTrunk(data ? 1 : 2);
            xpOrder.setAppUserId(null);
            this.updateById(xpOrder);
        }
        return xpOrderDetailVO;
    }
@@ -2819,7 +3243,25 @@
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setMessage(message);
        sendMessageDTO.setAppUserId(String.valueOf(appUserId));
        xpPushMessageClient.sendStatus(sendMessageDTO);
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("运维人员修改订单价格推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), order.getOrderNumber());
                }
            });
        }
        log.info("订单修改价格推送消息完毕");
    }
}