From c6d5c883a516577f89abc5972ed097d569245fc2 Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期六, 21 三月 2026 09:00:24 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java                      |    9 +
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java     |  216 ++++++++++++++++++++++++++++++++++++
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java                     |    8 +
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java   |    2 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java                |   11 +
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java |    2 
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java                |    3 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java             |    8 +
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java     |    2 
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java                    |    4 
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java     |    2 
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java           |    6 +
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java                   |    4 
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java       |    2 
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java      |    2 
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java   |   27 ++++
 16 files changed, 297 insertions(+), 11 deletions(-)

diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java
index 11ae823..39c5f60 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java
+++ b/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();
diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java
index f27f817..338e167 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java
+++ b/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队列的获取成功的数据
diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java
index 597568b..0c8490e 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpChargingRecord.java
+++ b/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 = "开始充电操作人")
diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java
index 54e4367..81c6106 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java
+++ b/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;
 
 
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java
index aacb416..01b8675 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/OperationRecordsVO.java
+++ b/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 = "开始剩余电量")
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java
index b035505..7288f54 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpChargingRecordVO.java
+++ b/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;
 
 }
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java
index 0ea25d2..955219c 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleCleanVO.java
+++ b/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;
 
 }
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java
index 6ec8a34..c364414 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleDetectionVO.java
+++ b/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;
 
 }
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java
index 085dba2..b3a9a8c 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehiclePreparationVO.java
+++ b/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;
 
 }
diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java
index 9587c2d..8043370 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/XpVehicleRepairVO.java
+++ b/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;
 
 }
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java
index 4ff3ae9..9aac451 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/TimeJobType.java
+++ b/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;
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java
new file mode 100644
index 0000000..5e79cbe
--- /dev/null
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java
@@ -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);
+        }
+    }
+}
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
index 0cf5465..33cf0b3 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
+++ b/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
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
index 9df98ec..584e57f 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
+++ b/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队列的获取成功的数据
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
index 54c27c6..95f4a0c 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
+++ b/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
      */
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
index ea031bb..f1fdc2c 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -2562,6 +2562,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) {
         // 查询订单信息
         Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId());

--
Gitblit v1.7.1