“mitao”
2026-03-20 255db1f1ddd23fcbebc86283b9c6c63e1d480dc1
fix:动态调价触发定时任务
1个文件已添加
15个文件已修改
308 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java
@@ -79,6 +79,12 @@
            }
            @Override
            public R<Integer> countActiveOrdersByCityId(Long cityId) {
                log.error("查询进行中订单数量失败,原因: {}", cause.getMessage());
                return R.ok(0);
            }
            @Override
            public R<?> popOrder(PopOrderDto dto) {
                log.error("订单出队失败,原因: {}", cause.getMessage());
                return R.fail();
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java
@@ -85,6 +85,15 @@
    @PostMapping("/inner/order/getOrderNum")
    R<Integer> getOrderNum(@RequestBody GetOrderNumDto dto);
    /**
     * 查询指定城市进行中的订单数量(status=1)
     *
     * @param cityId 开通城市ID
     * @return 进行中订单数量
     */
    @GetMapping("/inner/order/countActiveOrders")
    R<Integer> countActiveOrdersByCityId(@RequestParam("cityId") Long cityId);
    /**
     * 成功操作下发命令后调用 用于弹出redis队列的获取成功的数据
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java
@@ -48,7 +48,7 @@
    private String startChargingPicture;
    @ApiModelProperty(value = "开始充电时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime startTime;
    @ApiModelProperty(value = "结束剩余电量")
@@ -59,7 +59,7 @@
    private String endChargingPicture;
    @ApiModelProperty(value = "结束充电时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "开始充电操作人")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java
@@ -66,14 +66,14 @@
    private Long sendUserId;
    @ApiModelProperty(value = "送修时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime sendTime;
    @ApiModelProperty(value = "取回人")
    private Long returnUserId;
    @ApiModelProperty(value = "取回时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime returnTime;
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java
@@ -34,7 +34,7 @@
    private Long operationsUserId;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
    @ApiModelProperty(value = "开始剩余电量")
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java
@@ -31,7 +31,7 @@
    private String operatorEndName;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java
@@ -31,7 +31,7 @@
    private String operatorEndName;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java
@@ -34,7 +34,7 @@
    private String operatorEndName;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java
@@ -31,7 +31,7 @@
    private String operatorEndName;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java
@@ -31,7 +31,7 @@
    private String operatorEndName;
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime operationTime;
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java
@@ -6,7 +6,8 @@
 */
public enum TimeJobType {
    ELECTRONIC_EFFECT("electronic_effect","电子围栏生效"),
    ELECTRONIC_FAILURE("electronic_failure","电子围栏失效");
    ELECTRONIC_FAILURE("electronic_failure","电子围栏失效"),
    DYNAMIC_PRICING_CHECK("dynamic_pricing_check","动态调价供需检测");
    private String type;
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java
New file
@@ -0,0 +1,216 @@
package com.xiaopeng.operation.job.jobs;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpOpenCity;
import com.xiaopeng.api.model.operation.XpPricing;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.utils.DateUtils;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.operation.job.base.AbstractJob;
import com.xiaopeng.operation.job.base.TimeJobType;
import com.xiaopeng.operation.job.base.QuartzManager;
import com.xiaopeng.operation.job.utils.SpringContextsUtil;
import com.xiaopeng.operation.mapper.XpElectronicFenceMapper;
import com.xiaopeng.operation.mapper.XpOpenCityMapper;
import com.xiaopeng.operation.service.XpPricingService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 动态调价供需检测定时任务
 * <p>
 * 根据配置的供需计算周期(dynamicPricingJson.num1)定期执行:
 * 检测城市订单需求(status=1 进行中)与空闲车辆供给,
 * 满足调价条件时向 Redis 写入 DYNAMIC_PRICE_{openCityId} 触发标志。
 * 任务执行完后若 isDynamicPrice 仍为 1,自动注册下一次任务。
 * </p>
 *
 * @author mitao
 */
@Slf4j
public class DynamicPricingCheckJob extends AbstractJob {
    /**
     * 任务名称前缀
     */
    public static final String JOB_PREFIX = "dynamicPricingCheck_";
    private XpPricingService xpPricingService;
    private XpOrderClient xpOrderClient;
    private XpVehicleClient xpVehicleClient;
    private XpOpenCityMapper xpOpenCityMapper;
    private XpElectronicFenceMapper xpElectronicFenceMapper;
    private RedisService redisService;
    public DynamicPricingCheckJob() {
        super();
        this.xpPricingService = SpringContextsUtil.getBean(XpPricingService.class);
        this.xpOrderClient = SpringContextsUtil.getBean(XpOrderClient.class);
        this.xpVehicleClient = SpringContextsUtil.getBean(XpVehicleClient.class);
        this.xpOpenCityMapper = SpringContextsUtil.getBean(XpOpenCityMapper.class);
        this.xpElectronicFenceMapper = SpringContextsUtil.getBean(XpElectronicFenceMapper.class);
        this.redisService = SpringContextsUtil.getBean(RedisService.class);
    }
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        Long pricingId = maps.getLong("pricingId");
        log.info("========== 开始执行动态调价供需检测任务 pricingId={} ==========", pricingId);
        try {
            // 1. 查询定价配置,验证 isDynamicPrice=1
            XpPricing pricing = xpPricingService.getById(pricingId);
            if (pricing == null) {
                log.warn("动态调价任务跳过:定价配置不存在 pricingId={}", pricingId);
                return;
            }
            if (!Integer.valueOf(1).equals(pricing.getIsDynamicPrice())) {
                log.info("动态调价任务跳过:isDynamicPrice 已关闭 pricingId={}", pricingId);
                return;
            }
            if (StringUtils.isBlank(pricing.getDynamicPricingJson())) {
                log.warn("动态调价任务跳过:dynamicPricingJson 为空 pricingId={}", pricingId);
                return;
            }
            // 2. 解析 dynamicPricingJson 获取 num1/num2/num3
            JSONObject dynamicJson = JSONObject.parseObject(pricing.getDynamicPricingJson());
            Integer periodMinutes = dynamicJson.getInteger("num1"); // 供需计算周期(分钟)
            Integer orderThreshold = dynamicJson.getInteger("num2"); // 订单需求阈值
            Integer vehicleThreshold = dynamicJson.getInteger("num3"); // 车辆供给阈值
            if (periodMinutes == null || periodMinutes <= 0 || orderThreshold == null || vehicleThreshold == null) {
                log.warn("动态调价任务跳过:dynamicPricingJson 参数不完整 pricingId={}, num1={}, num2={}, num3={}",
                        pricingId, periodMinutes, orderThreshold, vehicleThreshold);
                return;
            }
            Long cityId = pricing.getCityId();
            if (cityId == null) {
                log.warn("动态调价任务跳过:定价配置 cityId 为空 pricingId={}", pricingId);
                return;
            }
            // 3. 通过 cityId 查询 XpOpenCity,获取 cityCode
            XpOpenCity openCity = xpOpenCityMapper.selectById(cityId);
            if (openCity == null) {
                log.warn("动态调价任务跳过:开通城市信息不存在 cityId={}", cityId);
                return;
            }
            String cityCode = openCity.getCityCode();
            if (StringUtils.isBlank(cityCode)) {
                log.warn("动态调价任务跳过:无法获取城市 code cityId={}", cityId);
                return;
            }
            // 4. 查询该城市下启用中(status=2)的电子围栏
            List<XpElectronicFence> fences = xpElectronicFenceMapper.selectList(
                    new LambdaQueryWrapper<XpElectronicFence>()
                            .eq(XpElectronicFence::getCityCode, cityCode)
                            .eq(XpElectronicFence::getStatus, 2));
            if (fences == null || fences.isEmpty()) {
                log.warn("动态调价任务跳过:未找到启用中的围栏 cityCode={}", cityCode);
                return;
            }
            // 5. 查询进行中订单数(status=1)
            int activeOrderCount = 0;
            try {
                R<Integer> orderResult = xpOrderClient.countActiveOrdersByCityId(cityId);
                if (orderResult != null && orderResult.getData() != null) {
                    activeOrderCount = orderResult.getData();
                }
            } catch (Exception e) {
                log.error("动态调价任务:查询进行中订单数失败 cityId={}", cityId, e);
            }
            // 6. 查询空闲车辆数(汇总所有围栏下 state=0 的车辆)
            int idleVehicleCount = 0;
            for (XpElectronicFence fence : fences) {
                if (fence.getId() == null) {
                    continue;
                }
                try {
                    R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByFenceId(fence.getId());
                    if (vehicleResult != null && vehicleResult.getData() != null) {
                        // listByFenceId 内部已过滤 state=0 且 operatingStatus=1 的空闲车辆
                        idleVehicleCount += vehicleResult.getData().size();
                    }
                } catch (Exception e) {
                    log.error("动态调价任务:查询围栏车辆失败 fenceId={}", fence.getId(), e);
                }
            }
            log.info("动态调价供需检测 pricingId={}, cityId={}, activeOrderCount={}, idleVehicleCount={}, orderThreshold={}, vehicleThreshold={}",
                    pricingId, cityId, activeOrderCount, idleVehicleCount, orderThreshold, vehicleThreshold);
            // 7. 判断是否满足调价条件:订单数 > 订单需求阈值 && 空闲车辆数 < 车辆供给阈值
            if (activeOrderCount > orderThreshold && idleVehicleCount < vehicleThreshold) {
                String redisKey = "DYNAMIC_PRICE_" + cityId;
                // 写入当前时间字符串,与现有 XpPricingUtil 消费侧兼容
                redisService.setCacheObject(redisKey, DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT));
                log.info("动态调价触发:已写入 Redis key={} pricingId={}", redisKey, pricingId);
            } else {
                log.info("动态调价未触发:供需条件不满足 pricingId={}", pricingId);
            }
        } catch (Exception e) {
            log.error("动态调价供需检测任务执行失败 pricingId={}", pricingId, e);
        } finally {
            // 8. 无论是否触发调价,若 isDynamicPrice 仍为 1,自动注册下一次任务
            scheduleNextRound(pricingId);
        }
        log.info("========== 动态调价供需检测任务执行完成 pricingId={} ==========", pricingId);
    }
    /**
     * 注册下一次动态调价检测任务(自我循环调度)
     *
     * @param pricingId 定价配置ID
     */
    private void scheduleNextRound(Long pricingId) {
        try {
            XpPricing pricing = xpPricingService.getById(pricingId);
            if (pricing == null || !Integer.valueOf(1).equals(pricing.getIsDynamicPrice())) {
                log.info("动态调价循环调度停止:isDynamicPrice 已关闭 pricingId={}", pricingId);
                return;
            }
            if (StringUtils.isBlank(pricing.getDynamicPricingJson())) {
                return;
            }
            JSONObject dynamicJson = JSONObject.parseObject(pricing.getDynamicPricingJson());
            Integer periodMinutes = dynamicJson.getInteger("num1");
            if (periodMinutes == null || periodMinutes <= 0) {
                return;
            }
            String jobName = JOB_PREFIX + pricingId;
            Date nextTriggerTime = new Date(System.currentTimeMillis() + periodMinutes * 60_000L);
            Map<String, Object> jobData = new HashMap<>();
            jobData.put("pricingId", pricingId);
            QuartzManager.addJob(DynamicPricingCheckJob.class, jobName,
                    TimeJobType.DYNAMIC_PRICING_CHECK, nextTriggerTime, jobData);
            log.info("动态调价下一次任务已注册 pricingId={}, 间隔={}分钟", pricingId, periodMinutes);
        } catch (Exception e) {
            log.error("动态调价循环调度注册失败 pricingId={}", pricingId, e);
        }
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -38,10 +38,14 @@
import com.xiaopeng.operation.service.IXpGeoQueryEntityService;
import com.xiaopeng.operation.service.XpPointService;
import com.xiaopeng.operation.service.XpPricingService;
import com.xiaopeng.operation.job.base.QuartzManager;
import com.xiaopeng.operation.job.base.TimeJobType;
import com.xiaopeng.operation.job.jobs.DynamicPricingCheckJob;
import com.xiaopeng.operation.utils.XpPricingUtil;
import com.xiaopeng.operation.utils.holiday.HolidayUtil;
import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
import com.xiaopeng.operation.vo.PricingPageListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.stereotype.Service;
@@ -63,6 +67,7 @@
 * @author liu
 * @since 2026-02-03
 */
@Slf4j
@Service
public class XpPricingServiceImpl extends ServiceImpl<XpPricingMapper, XpPricing> implements XpPricingService {
@@ -762,6 +767,28 @@
        update.setDynamicPricingJson(dto.getDynamicPricingJson());
        update.setIsDynamicPrice(dto.getIsDynamicPrice());
        this.updateById(update);
        // 动态调价 Quartz 任务调度
        String jobName = DynamicPricingCheckJob.JOB_PREFIX + dto.getId();
        if (Integer.valueOf(1).equals(dto.getIsDynamicPrice())
                && StringUtils.isNotBlank(dto.getDynamicPricingJson())) {
            JSONObject dynamicJson = JSONObject.parseObject(dto.getDynamicPricingJson());
            Integer periodMinutes = dynamicJson.getInteger("num1");
            if (periodMinutes != null && periodMinutes > 0) {
                // 先移除可能存在的旧任务,再注册新任务(num1 分钟后首次执行)
                QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
                Date triggerTime = new Date(System.currentTimeMillis() + periodMinutes * 60_000L);
                Map<String, Object> jobData = new HashMap<>();
                jobData.put("pricingId", dto.getId());
                QuartzManager.addJob(DynamicPricingCheckJob.class, jobName,
                        TimeJobType.DYNAMIC_PRICING_CHECK, triggerTime, jobData);
                log.info("动态调价任务已注册 pricingId={}, 供需计算周期={}分钟", dto.getId(), periodMinutes);
            }
        } else {
            // 关闭动态调价时,移除已存在的任务
            QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
            log.info("动态调价任务已移除 pricingId={}", dto.getId());
        }
    }
    @Override
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -141,6 +141,17 @@
        return R.ok(xpOrderService.getOrderNum(dto));
    }
    /**
     * 查询指定城市进行中的订单数量(status=1)
     *
     * @param cityId 开通城市ID
     * @return 进行中订单数量
     */
    @GetMapping("/inner/order/countActiveOrders")
    public R<Integer> countActiveOrdersByCityId(@RequestParam("cityId") Long cityId) {
        return R.ok(xpOrderService.countActiveOrdersByCityId(cityId));
    }
    /**
     * 成功操作下发命令后调用 用于弹出redis队列的获取成功的数据
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
@@ -200,6 +200,14 @@
    Integer getOrderNum(GetOrderNumDto dto);
    /**
     * 查询指定城市进行中的订单数量(status=1)
     *
     * @param cityId 开通城市ID
     * @return 进行中订单数量
     */
    Integer countActiveOrdersByCityId(Long cityId);
    /**
     * 保存车辆位置信息
     * @param orderTrajectory
     */
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -2547,6 +2547,14 @@
    }
    @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());