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