From 2b306afe79cd8096dd9394b0d8d04ff467b7e09c Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期五, 10 四月 2026 22:38:18 +0800
Subject: [PATCH] fix:车辆无XPUID返回内容修改、围栏自动停用补偿定时任务
---
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderPageVO.java | 7 +
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java | 30 ++++++
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/job/jobs/ElectronicEffectJob.java | 10 -
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceService.java | 11 +-
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java | 21 ++++
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java | 3
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java | 85 ++++++++++++-----
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java | 12 --
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/schedule/ElectronicFenceFailureCompensationTask.java | 81 ++++++++++++++++
9 files changed, 210 insertions(+), 50 deletions(-)
diff --git a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
index c8612f4..7806135 100644
--- a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
+++ b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -290,16 +290,8 @@
if (mqttPublishDto.getCode() == 200) {
if(!dto.getOrderId().contains("XU")){
- Map<String, Object> cancelContext = new HashMap<>();
- cancelContext.put("orderId", dto.getOrderId());
- cancelContext.put("vin", dto.getVin());
- cancelContext.put("cancelScene", StringUtils.isNotEmpty(dto.getCancelScene())
- ? dto.getCancelScene()
- : CancelOrderSceneEnum.NORMAL_CANCEL.getCode());
- redisService.setCacheObject("CANCEL_ORDER_CONTEXT:" + taskId,
- JSONObject.toJSONString(cancelContext), 30L, TimeUnit.MINUTES);
- log.info("记录取消订单上下文成功,orderId: {}, vin: {}, taskId: {}, cancelScene: {}",
- dto.getOrderId(), dto.getVin(), taskId, cancelContext.get("cancelScene"));
+ // 正常订单处理
+ redisService.setCacheObject(String.valueOf(sequence), "cancelOrder_" + dto.getOrderId() + "_" + dto.getVin(), 30l, TimeUnit.MINUTES);
}
return R.ok(true);
}
diff --git a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
index b79d9e2..468af59 100644
--- a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
+++ b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -72,7 +72,7 @@
@Slf4j
@Service
public class KafkaConsumerService {
- private static final String CANCEL_ORDER_CONTEXT_PREFIX = "CANCEL_ORDER_CONTEXT:";
+ private static final String REASSIGN_CANCEL_CONTEXT_PREFIX = "REASSIGN_CANCEL_CONTEXT:";
@Resource
@@ -1166,12 +1166,18 @@
//已取消
if(!orderId.contains("XU")){
String taskId = orderStatusInfo.getTaskId();
- JSONObject cancelContext = getCancelOrderContext(taskId);
- if (shouldSkipCancelForReassign(cancelContext)) {
+ JSONObject reassignCancelContext = resolveReassignCancelContext(orderId, orderStatusInfo);
+ if (Objects.nonNull(reassignCancelContext)) {
log.info("改派旧车取消回调,跳过订单取消处理,orderId: {}, taskId: {}, cancelScene: {}, context: {}",
- orderId, taskId, cancelContext.getString("cancelScene"), cancelContext);
+ orderId, taskId, reassignCancelContext.getString("cancelScene"), reassignCancelContext);
//响应消息
- responseMessage(sequence, cancelContext.getString("vin"));
+ String responseVin = resolveReassignCancelResponseVin(reassignCancelContext);
+ if (StringUtils.isNotEmpty(responseVin)) {
+ responseMessage(sequence, responseVin);
+ } else {
+ log.warn("改派旧车取消回调未找到响应VIN,orderId: {}, taskId: {}, context: {}",
+ orderId, taskId, reassignCancelContext);
+ }
return;
}
if(orderId.contains("TEST")){
@@ -1212,11 +1218,11 @@
//行程中取消订单,按照行程结束处理
buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence);
xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
- redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS);
+ redisService.setCacheObject("ORDER_STATUS:" + orderId, OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS);
}else{
buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED, sequence);
xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.CANCELED.getCode());
- redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS);
+ redisService.setCacheObject("ORDER_STATUS:" + orderId, OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS);
}
}
}
@@ -1381,33 +1387,62 @@
}
}
- /**
- * 根据taskId获取订单取消的上下文信息
- * @param taskId
- * @return
- */
- private JSONObject getCancelOrderContext(String taskId) {
- if (StringUtils.isEmpty(taskId)) {
+ private JSONObject getReassignCancelContext(String orderId) {
+ if (StringUtils.isEmpty(orderId)) {
return null;
}
- Object cacheObject = redisService.getCacheObject(CANCEL_ORDER_CONTEXT_PREFIX + taskId);
+ Object cacheObject = redisService.getCacheObject(REASSIGN_CANCEL_CONTEXT_PREFIX + orderId);
if (cacheObject == null) {
return null;
}
return JSON.parseObject(cacheObject.toString());
}
- /**
- * 判断是否是改派旧车取消回调,是则跳过订单取消处理
- * @param cancelContext
- * @return
- */
- private boolean shouldSkipCancelForReassign(JSONObject cancelContext) {
- if (cancelContext == null) {
- return false;
+ private JSONObject resolveReassignCancelContext(String orderId, OrderStatusInfo orderStatusInfo) {
+ if (OrderStateChangeSource.ORDER_STATE_CHANGE_SOURCE_VEHICLE != orderStatusInfo.getChangeSource()) {
+ return null;
}
- return CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE == CancelOrderSceneEnum.fromCode(
- cancelContext.getString("cancelScene"));
+ JSONObject cancelContext = getReassignCancelContext(orderId);
+ if (cancelContext == null) {
+ return null;
+ }
+ if (CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE != CancelOrderSceneEnum.fromCode(
+ cancelContext.getString("cancelScene"))) {
+ return null;
+ }
+ R<XpOrder> orderResult = xpOrderClient.queryOrderById(Long.parseLong(orderId));
+ XpOrder xpOrder = orderResult == null ? null : orderResult.getData();
+ if (xpOrder == null) {
+ log.warn("改派取消回调识别失败,订单不存在,orderId: {}, context: {}", orderId, cancelContext);
+ return null;
+ }
+ Long newVehicleId = cancelContext.getLong("newVehicleId");
+ Integer currentStatus = xpOrder.getStatus();
+ boolean vehicleMatched = Objects.nonNull(newVehicleId) && Objects.equals(newVehicleId, xpOrder.getVehicleId());
+ boolean statusMatched = Objects.nonNull(currentStatus) && currentStatus > 0 && currentStatus < 8;
+ if (vehicleMatched && statusMatched) {
+ return cancelContext;
+ }
+ log.info("改派取消回调未命中专用上下文,orderId: {}, currentVehicleId: {}, newVehicleId: {}, currentStatus: {}",
+ orderId, xpOrder.getVehicleId(), newVehicleId, currentStatus);
+ return null;
+ }
+
+ private String resolveReassignCancelResponseVin(JSONObject cancelContext) {
+ if (cancelContext == null) {
+ return null;
+ }
+ String oldVehicleVin = cancelContext.getString("oldVehicleVin");
+ if (StringUtils.isNotEmpty(oldVehicleVin)) {
+ return oldVehicleVin;
+ }
+ Long oldVehicleId = cancelContext.getLong("oldVehicleId");
+ if (Objects.isNull(oldVehicleId)) {
+ return null;
+ }
+ R<XpVehicle> vehicleResult = xpVehicleClient.queryById(oldVehicleId);
+ XpVehicle xpVehicle = vehicleResult == null ? null : vehicleResult.getData();
+ return xpVehicle == null ? null : xpVehicle.getVehicleVin();
}
/**
diff --git a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
index 2fdfcc3..b53bc0a 100644
--- a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
+++ b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
@@ -8,6 +8,7 @@
import com.xiaopeng.api.feignClient.automaticPilot.XPUClient;
import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo;
import com.xiaopeng.api.vo.automaticPilot.protobuf.*;
+import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.uuid.UUID;
import lombok.extern.slf4j.Slf4j;
@@ -210,7 +211,7 @@
log.info("getMqttPublishTopic vin,{},xpuIdMapping,{}", vin, JSON.toJSONString(xpuIdMapping));
if (xpuIdMapping == null || StringUtils.isEmpty(xpuIdMapping.get(XPU_ID_TYPE)) ) {
log.error("根据vin查询车辆xpuid信息为空,vin={}", vin);
- throw new RuntimeException("根据vin查询车辆xpuid信息为空");
+ throw new ServiceException("根据vin查询车辆xpuid信息为空");
}
return xpuIdMapping.get(XPU_ID_TYPE);
}
diff --git a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/job/jobs/ElectronicEffectJob.java b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/job/jobs/ElectronicEffectJob.java
index 6b02e45..58ce357 100644
--- a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/job/jobs/ElectronicEffectJob.java
+++ b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/job/jobs/ElectronicEffectJob.java
@@ -41,15 +41,7 @@
xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList);
}else{
// 电子围栏失效
- XpElectronicFence electronicFence = xpElectronicFenceService.getById(electronicId);
- electronicFence.setStatus(3);
- xpElectronicFenceService.updateById(electronicFence);
- List<XpElectronicFenceArea> electronicFenceAreaList = xpElectronicFenceAreaService.lambdaQuery().eq(XpElectronicFenceArea::getElectronicId, electronicId).list();
- // 设置为禁用
- for(XpElectronicFenceArea electronicFenceArea : electronicFenceAreaList){
- electronicFenceArea.setAreaStatus(2);
- }
- xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList);
+ xpElectronicFenceService.expireFence(electronicId);
}
}catch(Exception e){
diff --git a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/schedule/ElectronicFenceFailureCompensationTask.java b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/schedule/ElectronicFenceFailureCompensationTask.java
new file mode 100644
index 0000000..c05b9a1
--- /dev/null
+++ b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/schedule/ElectronicFenceFailureCompensationTask.java
@@ -0,0 +1,81 @@
+package com.xiaopeng.map.schedule;
+
+import com.xiaopeng.api.model.operation.XpElectronicFence;
+import com.xiaopeng.map.service.XpElectronicFenceService;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * 电子围栏失效补偿定时任务
+ */
+@Slf4j
+@Component
+public class ElectronicFenceFailureCompensationTask {
+
+ private static final String LOCK_KEY = "MAP:ELECTRONIC_FENCE:FAILURE_COMPENSATE";
+ private static final int LOCK_WAIT_SECONDS = 0;
+ private static final int LOCK_LEASE_SECONDS = 15;
+
+ @Resource
+ private XpElectronicFenceService xpElectronicFenceService;
+
+ @Resource
+ private RedissonClient redissonClient;
+
+ @Scheduled(fixedDelay = 10 * 1000L)
+ public void compensateExpiredFence() {
+ RLock lock = redissonClient.getLock(LOCK_KEY);
+ boolean locked = false;
+ try {
+ locked = lock.tryLock(LOCK_WAIT_SECONDS, LOCK_LEASE_SECONDS, TimeUnit.SECONDS);
+ if (!locked) {
+ return;
+ }
+
+ LocalDateTime now = LocalDateTime.now();
+ List<XpElectronicFence> expiredFenceList = xpElectronicFenceService.lambdaQuery()
+ .eq(XpElectronicFence::getFailureType, 2)
+ .le(XpElectronicFence::getFailureTime, now)
+ .in(XpElectronicFence::getStatus, 1, 2)
+ .list();
+ if (expiredFenceList == null || expiredFenceList.isEmpty()) {
+ return;
+ }
+
+ List<Long> electronicIds = expiredFenceList.stream()
+ .map(XpElectronicFence::getId)
+ .collect(Collectors.toList());
+ log.info("电子围栏失效补偿开始, count={}, ids={}", electronicIds.size(), electronicIds);
+ for (Long electronicId : electronicIds) {
+ try {
+ xpElectronicFenceService.expireFence(electronicId);
+ } catch (Exception e) {
+ log.error("电子围栏失效补偿单条处理异常, electronicId={}", electronicId, e);
+ }
+ }
+ log.info("电子围栏失效补偿完成, count={}, ids={}", electronicIds.size(), electronicIds);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("电子围栏失效补偿任务获取锁被中断", e);
+ } catch (Exception e) {
+ log.error("电子围栏失效补偿任务执行异常", e);
+ } finally {
+ try {
+ if (locked && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ } catch (Exception e) {
+ log.warn("释放电子围栏失效补偿锁失败 lockKey={}", LOCK_KEY, e);
+ }
+ }
+ }
+}
diff --git a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceService.java b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceService.java
index 2efed47..b58fc71 100644
--- a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceService.java
+++ b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceService.java
@@ -37,9 +37,10 @@
* @return
*/
List<XpElectronicFence> getList();
+
+ /**
+ * 将围栏置为已停用,并同步禁用围栏区域
+ * @param electronicId 围栏ID
+ */
+ void expireFence(Long electronicId);
}
-
-
-
-
-
diff --git a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
index 142918b..a54e6b9 100644
--- a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
+++ b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
@@ -958,6 +958,36 @@
return list();
}
+ @Override
+ @Transactional
+ @ShardingSphereTransactionType(TransactionType.BASE)
+ public void expireFence(Long electronicId) {
+ if (electronicId == null) {
+ return;
+ }
+ XpElectronicFence electronicFence = this.getById(electronicId);
+ if (electronicFence == null || electronicFence.getStatus() == null) {
+ return;
+ }
+ Integer status = electronicFence.getStatus();
+ if (status != 1 && status != 2) {
+ return;
+ }
+ electronicFence.setStatus(3);
+ this.updateById(electronicFence);
+
+ List<XpElectronicFenceArea> electronicFenceAreaList = xpElectronicFenceAreaService.lambdaQuery()
+ .eq(XpElectronicFenceArea::getElectronicId, electronicId)
+ .list();
+ if (CollUtil.isEmpty(electronicFenceAreaList)) {
+ return;
+ }
+ for (XpElectronicFenceArea electronicFenceArea : electronicFenceAreaList) {
+ electronicFenceArea.setAreaStatus(2);
+ }
+ xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList);
+ }
+
/**
* 计算围栏中心点
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderPageVO.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderPageVO.java
index 80aa692..a035113 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderPageVO.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpOrderPageVO.java
@@ -1,5 +1,6 @@
package com.xiaopeng.order.model.vo;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -59,4 +60,10 @@
private BigDecimal orderMoney;
@ApiModelProperty(value = "状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成")
private Integer status;
+
+ @ApiModelProperty(value = "下单站点名称")
+ private String startPointName;
+
+ @ApiModelProperty(value = "下单终点站点名称")
+ private String endPointName;
}
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 d2d3593..42a31b6 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
@@ -137,6 +137,9 @@
@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;
private final XpVehicleClient xpVehicleClient;
@@ -969,6 +972,8 @@
cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
orderMissionClient.cancelOrder(cancelDto);
+ cacheReassignCancelContext(orderId, oldVehicleId, newVehicleId,
+ oldVehicle.getVehicleVin(), currentStatus);
log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}, taskId: {}, cancelScene: {}",
orderId, oldVehicle.getVehicleVin(), cancelDto.getTaskId(), cancelDto.getCancelScene());
@@ -1113,6 +1118,22 @@
}
+ 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);
+ }
+
/**
* 为原车辆创建返程巡游订单
* <p>
--
Gitblit v1.7.1