From fa93c9eefcbfcb7ba8b7a9d0b41ba2b4e3523ae5 Mon Sep 17 00:00:00 2001
From: xuhy <3313886187@qq.com>
Date: 星期三, 22 四月 2026 11:07:23 +0800
Subject: [PATCH] [fix] 胶囊改进
---
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java | 4 ++
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java | 17 ++++++++
xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml | 24 ++++++++++++
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java | 57 ++++++++++++++++++++++++++++
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java | 5 ++
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java | 2
6 files changed, 106 insertions(+), 3 deletions(-)
diff --git a/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java b/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java
index 21d4949..be6f0a6 100644
--- a/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java
+++ b/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java
@@ -57,7 +57,7 @@
}
- private static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
+ public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
//创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);
return geoCurve.getEllipsoidalDistance();
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 fc9fb2a..7c1f36f 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
@@ -16,10 +16,10 @@
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
+import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.common.core.domain.R;
-import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.WebUtils;
import com.xiaopeng.common.core.web.page.PageInfo;
@@ -341,6 +341,21 @@
}
/**
+ * 获取用户快捷胶囊 历史 时段 终点高点
+ */
+ @ApiOperation(value = "获取首页快捷胶囊推荐站点", notes = "根据当前起点和用户近30天有效订单,按场景优先推荐目的地;无匹配时返回空数据", tags = {"小程序-首页快捷胶囊"}, response = XpPointInfoVo.class)
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "startPointId", value = "当前首页起点站点ID", required = true, dataType = "Long", paramType = "query")
+ })
+ @GetMapping("/api/v1/mini-program/order/quick-capsule")
+ @XpClientCheck(checkToken = false, checkOtpToken = true)
+ public R<NearestNextVo> quickCapsule(@RequestParam Long startPointId,HttpServletRequest request) {
+ String uid = request.getHeader("XP-Uid");
+ return R.ok(xpOrderService.quickCapsule(uid,startPointId));
+
+ }
+
+ /**
* 获取订单详情
*/
@PutMapping("/api/v1/mini-program/order/orderDetail/{orderId}")
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java
index d3f97ee..79214a4 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java
@@ -6,12 +6,12 @@
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.order.model.query.XpHistoryOrderListQuery;
import com.xiaopeng.order.model.vo.XpOrderHistoryListVO;
-import com.xiaopeng.order.model.vo.XpOrderHistoryVO;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
+import java.time.LocalTime;
import java.util.List;
/**
@@ -74,4 +74,7 @@
List<XpOrder> listUserRecentValidOrders(@Param("uid") Long uid, @Param("startTime") LocalDateTime startTime);
+ List<Long> timeSceneOrders(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDateTime endDate, @Param("startMoment") LocalTime startMoment, @Param("endMoment") LocalTime endMoment, @Param("userId") Long userId);
+
+ List<Long> frequencyOrders(LocalDate startDate, LocalDateTime endDate, LocalTime startMoment, LocalTime endMoment, Long userId);
}
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 8631ac4..a0e59ee 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
@@ -8,6 +8,7 @@
import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
+import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.order.FareBreakdownVo;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
@@ -105,6 +106,8 @@
* @return
*/
XpPointInfoVo getUserQuickCapsule(String uid, Long startPointId);
+
+ NearestNextVo quickCapsule(String uid, Long startPointId);
/**
* 获取历史下单成功起点10条数据列表
@@ -262,4 +265,5 @@
* @return
*/
OrderInfoVo getOrderInfo(Long orderId);
+
}
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 154beb7..ddbdef1 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
@@ -31,6 +31,7 @@
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.account.SysGroupMenuClient;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
+import com.xiaopeng.api.feignClient.account.XpAppUserCollectAddrClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.automaticPilot.VehicleBuriedPointClient;
@@ -49,6 +50,7 @@
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderStatus;
+import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
@@ -96,6 +98,8 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
+import org.gavaghan.geodesy.Ellipsoid;
+import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -1311,6 +1315,59 @@
return null;
}
+ @Resource
+ private XpAppUserCollectAddrClient xpAppUserCollectAddrClient;
+ @Override
+ public NearestNextVo quickCapsule(String uid, Long startPointId) {
+
+ Long userId = Long.valueOf(uid);
+ // - 新用户处理: 历史订单数 < 3单或无匹配数据时,隐藏该胶囊。
+ Long validHistoryCount = this.baseMapper.countUserValidHistoryOrders(userId);
+ if (validHistoryCount == null || validHistoryCount < 3) return null;
+
+ LocalDateTime now = LocalDateTime.now();
+ LocalTime startMoment = now.minusHours(1).toLocalTime();
+ LocalTime endMoment = now.plusHours(1).toLocalTime();
+ LocalDate startDate = now.minusMonths(1).toLocalDate();
+ LocalDateTime endDate = now.plusMonths(1);
+
+ // 时段强相关目的地(场景触发)当前时间点(当前时间 ± 1小时)内,过去30天内前往次数最多的目的地。
+ List<Long> endPointId = this.baseMapper.timeSceneOrders(startDate, endDate, startMoment, endMoment, userId);
+ // 判定条件: 若当前时段内无明显的规律性目的地(例如:用户在周六下午偶尔出门,且目的地不固定),则推荐用户过去30天内订单总量最高的前1名地址(需排除当前起点)。
+ endPointId.addAll(this.baseMapper.frequencyOrders(startDate, endDate, startMoment, endMoment, userId));
+
+ Integer minOrderDistance = getMinOrderDistanceSafely(uid, startPointId);
+ if (minOrderDistance == null) return null;//获取用户最短可发单距离失败
+ XpPoint start = getPointById(startPointId);
+ GlobalCoordinates startCoordinates = new GlobalCoordinates(start.getPointLon(), start.getPointLat());
+ List<Long> pointIdsByUserId = Optional.ofNullable(xpAppUserCollectAddrClient.getPointIdsByUserId(Long.valueOf(uid)).getData())
+ .orElse(new ArrayList<>());
+ for (Long pointId : endPointId) {
+ XpPoint endPoint = getPointById(pointId);
+ // 计算直线距离,如果endPoint到startPoint的距离大于minOrderDistance,则返回该点
+ GlobalCoordinates endCoordinates = new GlobalCoordinates(endPoint.getPointLon(), endPoint.getPointLat());
+ double distanceMeter = GeodesyUtil.getDistanceMeter(startCoordinates, endCoordinates, Ellipsoid.WGS84);
+ if (distanceMeter > minOrderDistance) {
+ NearestNextVo ret = new NearestNextVo();
+ ret.setId(endPoint.getId());
+ ret.setName(endPoint.getPointName());
+ ret.setLatitude(endPoint.getPointLat());
+ ret.setLongitude(endPoint.getPointLon());
+ ret.setDistance(new BigDecimal(distanceMeter).setScale(2, RoundingMode.HALF_UP).doubleValue());
+ ret.setAddress(endPoint.getPointAddress());
+ ret.setTime(endPoint.getParkingTimeLimit());
+ ret.setElectronicAreaId(endPoint.getElectronicAreaId());
+ // 判断是否收藏
+ if(pointIdsByUserId.contains(endPoint.getId())){
+ ret.setIsCollect(1);
+ }
+ return ret;
+ }
+ }
+ return null;
+ }
+
+
private RecommendationCandidate buildSceneCandidate(List<XpOrder> recentOrders, LocalDateTime now, XpPoint startPoint, Integer minOrderDistance) {
DaySceneType currentSceneType = resolveDaySceneType(now.toLocalDate());
Set<Integer> targetHours = buildTargetHours(now.getHour());
diff --git a/xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml b/xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml
index 3c3cddc..4a60856 100644
--- a/xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml
+++ b/xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml
@@ -100,4 +100,28 @@
ORDER BY create_time DESC
</select>
+ <select id="timeSceneOrders" resultType="java.lang.Long">
+ SELECT
+ end_point_id
+ FROM xp_order
+ WHERE app_user_id = #{userId}
+ AND is_deleted = 0
+ AND status IN (9, 10)
+ AND DATE(create_time) BETWEEN #{startDate} AND #{endDate}
+ AND TIME(create_time) BETWEEN #{startTime} AND #{endTime}
+ GROUP BY end_point_id
+ ORDER BY COUNT(*) DESC
+ </select>
+ <select id="frequencyOrders" resultType="java.lang.Long">
+ SELECT
+ end_point_id
+ FROM xp_order
+ WHERE app_user_id = #{userId}
+ AND is_deleted = 0
+ AND status IN (9, 10)
+ AND DATE(create_time) BETWEEN #{startDate} AND #{endDate}
+ GROUP BY end_point_id
+ ORDER BY COUNT(*) DESC
+ </select>
+
</mapper>
--
Gitblit v1.7.1