xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpPricingClientFallbackFactory.java
@@ -34,10 +34,11 @@ } @Override public R<?> saveXpGeoQueryEntity(XpGeoQueryEntity xpGeoQueryEntity) { log.error("保存XpGeoQueryEntity失败", cause); public R<?> updateXpGeoQueryEntity(String orderId) { log.error("更新XpGeoQueryEntity失败", cause); return R.fail(); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpPricingClient.java
@@ -27,8 +27,8 @@ /** * 保存XpGeoQueryEntity */ @PostMapping("/inner/saveXpGeoQueryEntity") R<?> saveXpGeoQueryEntity(@RequestBody XpGeoQueryEntity xpGeoQueryEntity); @PostMapping("/inner/updateXpGeoQueryEntity") R<?> updateXpGeoQueryEntity(@RequestParam String orderId); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpGeoQueryEntity.java
@@ -30,7 +30,7 @@ * 时间戳 */ @Field("timestamp") private Date timestamp; private Long timestamp; /** * 秒数 @@ -81,11 +81,11 @@ this.location = location; } public Date getTimestamp() { public Long getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { public void setTimestamp(Long timestamp) { this.timestamp = timestamp; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/RouteAndFareVo.java
@@ -1,5 +1,6 @@ package com.xiaopeng.api.vo.operation; import com.xiaopeng.api.vo.order.XpPricingCardVo; import io.swagger.annotations.ApiModel; @lombok.Data @@ -10,4 +11,7 @@ private FareVo fareEstimate; private XpPricingCardVo xpPricingCard; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPricingController.java
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.Date; /** * <p> @@ -49,29 +50,28 @@ } @PostMapping("/base/v1/mini-program/navigation/route-and-fare") @ApiOperation(value = "导航-获取路线和费用",tags = {"小程序-获取路线和费用"},response = RouteAndFareVo.class) @ApiOperation(value = "导航-获取路线和费用", tags = {"小程序-获取路线和费用"}, response = RouteAndFareVo.class) @XpClientCheck(checkToken = false, checkOtpToken = true) public R<RouteAndFareVo> getRouteAndFare(@RequestBody @Valid RouteAndFareDto routeAndFareDto, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpPricingService.getRouteAndFare(routeAndFareDto,uid)); return R.ok(xpPricingService.getRouteAndFare(routeAndFareDto, uid)); } // 根据开通城市 获取定价 @GetMapping("/getPricingByCityId/{cityId}") public R<XpPricing> getPricingByCityId(@PathVariable("cityId")Long cityId) { public R<XpPricing> getPricingByCityId(@PathVariable("cityId") Long cityId) { XpPricing pricing = xpPricingService.lambdaQuery().eq(XpPricing::getCityId, cityId).last("limit 1").one(); return R.ok(pricing); } @GetMapping("/base/v1/mini-program/pricing/rules/{openCityId}") @ApiOperation(value = "获取费用规则",tags = {"小程序-根据开通城市获取费用规则"},response = String.class) @ApiOperation(value = "获取费用规则", tags = {"小程序-根据开通城市获取费用规则"}, response = String.class) public R<?> getPricingRules(@PathVariable Long openCityId) { XpPricing xpPricing = xpPricingService.getOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, openCityId).eq(XpPricing::getPricingType, 1).last("limit 1")); if(xpPricing!=null){ if (xpPricing != null) { return R.ok(xpPricing.getPriceRule()); } return R.ok(""); @@ -84,20 +84,20 @@ * @return */ @PostMapping("/base/v1/mini-program/pricing/getWaitTime") @ApiOperation(value = "获取等待时间",tags = {"小程序-获取等待时间"},response = Integer.class) public R<Integer> getWaitTime(@RequestBody LonLatDto dto){ return R.ok(xpPricingService.getWaitTime(dto.getLongitude(),dto.getLatitude())); @ApiOperation(value = "获取等待时间", tags = {"小程序-获取等待时间"}, response = Integer.class) public R<Integer> getWaitTime(@RequestBody LonLatDto dto) { return R.ok(xpPricingService.getWaitTime(dto.getLongitude(), dto.getLatitude())); } /** * 保存信息 * @param xpGeoQueryEntity * @param * @return */ @PostMapping("/inner/saveXpGeoQueryEntity") public R<?> saveXpGeoQueryEntity(@RequestBody XpGeoQueryEntity xpGeoQueryEntity){ xpGeoQueryEntityService.save(xpGeoQueryEntity); @PostMapping("/inner/updateXpGeoQueryEntity") public R<?> updateXpGeoQueryEntity(@RequestParam String orderId) { xpGeoQueryEntityService.updateByOrderId(orderId); return R.ok(); } @@ -106,7 +106,7 @@ * 播单 */ @PostMapping("/base/v1/mini-program/order/save") @ApiOperation(value = "保存订单",tags = {"小程序-保存订单"}) @ApiOperation(value = "保存订单", tags = {"小程序-保存订单"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R<SaveOrderVo> saveOrder(@RequestBody @Validated XpOrderDto dto, HttpServletRequest request) { String uid = request.getHeader("XP-Uid"); @@ -115,8 +115,6 @@ saveOrderVo.setOrderId(l); return R.ok(saveOrderVo); } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/IXpGeoQueryEntityService.java
@@ -20,6 +20,9 @@ String time ); /** * 保存地理查询实体 * @param entity 地理查询实体 @@ -27,6 +30,12 @@ */ XpGeoQueryEntity save(XpGeoQueryEntity entity); /** * 修改 */ XpGeoQueryEntity updateByOrderId(String orderId); /** * 根据ID查询实体 * @param id 实体ID xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpBannerServiceImpl.java
@@ -27,7 +27,6 @@ @Override public List<XpBannerListVo> getXpBannerList() { LambdaQueryWrapper<XpBanner> wrapper = new LambdaQueryWrapper<>(); // TODO 魔法数字 wrapper.eq(XpBanner::getBannerStatus,1); // 当前时间在开始和结束时间范围内 wrapper.ge(XpBanner::getStartTime,System.currentTimeMillis()); xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpGeoQueryEntityServiceImpl.java
@@ -1,17 +1,25 @@ package com.xiaopeng.operation.service.impl; import com.xiaopeng.api.model.operation.XpGeoQueryEntity; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; import com.xiaopeng.operation.repository.XpGeoQueryEntityRepository; import com.xiaopeng.operation.service.IXpGeoQueryEntityService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.stream.Collectors; /** * MongoDB 地理查询服务实现类 @@ -21,6 +29,9 @@ @Autowired private XpGeoQueryEntityRepository repository; @Autowired private MongoTemplate mongoTemplate; /** * 通过经纬度查询固定范围500米内、一周内、指定时段的数据 @@ -35,26 +46,43 @@ double latitude, String time ) { // 创建中心点坐标 Point point = new Point(longitude, latitude); // 设置距离范围为500米 Distance distance = new Distance(0.5, Metrics.KILOMETERS); // 0.5公里 = 500米 // 计算一周前的时间 // // 计算一周前的时间 Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.add(Calendar.DAY_OF_YEAR, -7); Date startTime = calendar.getTime(); Long startTime = calendar.getTime().getTime(); // 执行查询 - 使用新的方法,包含时段过滤 return repository.findByLocationNearAndTimestampAfterAndTimeAndStatusGreaterThan( point, 500, startTime, time, // 时段过滤 1 // 状态大于1 // 1. 创建查询点 Point referencePoint = new Point(longitude, latitude); // 2. 构建 NearQuery - 完全使用 NearQuery 的 API NearQuery nearQuery = NearQuery.near(referencePoint, Metrics.KILOMETERS) .maxDistance(0.5) // 转成公里 .spherical(true); // 3.时间>startTime time = time参数 // 3. 创建额外的查询条件 Query query = new Query(); query.addCriteria(Criteria.where("timestamp").gte(startTime)); query.addCriteria(Criteria.where("time").is(time)); // 将 NearQuery 和额外的查询条件合并 nearQuery.query(query); // 4. 执行查询 - 明确指定集合名 GeoResults<XpGeoQueryEntity> geoResults = mongoTemplate.geoNear( nearQuery, XpGeoQueryEntity.class, "xp_geo_query_entity" // 明确指定集合名,避免映射错误 ); // 5. 提取结果 return geoResults.getContent().stream() .map(geoResult -> geoResult.getContent()) .collect(Collectors.toList()); } /** @@ -67,6 +95,25 @@ return repository.save(entity); } @Override public XpGeoQueryEntity updateByOrderId(String orderId) { Query query = new Query(Criteria.where("orderId").is(orderId)); XpGeoQueryEntity xpGeoQueryEntity = mongoTemplate.findOne(query, XpGeoQueryEntity.class); Long timestamp = xpGeoQueryEntity.getTimestamp(); long time = new Date().getTime(); // 计算2个时间的秒数差 long seconds = (time- timestamp) / 1000; Update update = new Update().set("seconds", seconds).set("status", 1); if(xpGeoQueryEntity.getStatus()==0){ mongoTemplate.findAndModify(query, update, XpGeoQueryEntity.class); } return null; } /** * 根据ID查询实体 * @param id 实体ID xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -20,6 +20,7 @@ import com.xiaopeng.api.vo.operation.FareVo; import com.xiaopeng.api.vo.operation.RouteAndFareVo; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.api.vo.order.XpPricingCardVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.exception.ServiceException; @@ -35,12 +36,13 @@ 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.XpPricingCardVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.stereotype.Service; import javax.annotation.PreDestroy; import javax.annotation.Resource; import java.time.Duration; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.*; @@ -89,8 +91,6 @@ @Resource private XpElectronicFenceAreaMapper xpElectronicFenceAreaMapper; @Resource private XpVehicleClient xpVehicleClient; @Resource private XpPointMapper xpPointMapper; @@ -206,6 +206,8 @@ // ); XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); // 3. 并行执行远程服务调用 判断是否同一经营区域 CompletableFuture<R<Boolean>> diagnosisAreaFuture = CompletableFuture.supplyAsync( () -> xpMapClient.diagnosisArea(routeAndFareDto), @@ -274,6 +276,9 @@ RouteAndFareVo routeAndFareVo = new RouteAndFareVo(); // routeAndFareVo.setRoute(routeVo); routeAndFareVo.setXpPricingCard(xpPricingCardVo); FareVo fareVo = new FareVo(); // fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000); // fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60); @@ -333,7 +338,7 @@ return 1; } else { // 已完成接单的数据 List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() > 1).collect(Collectors.toList()); List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() == 1).collect(Collectors.toList()); // 计算平均等待时间 OptionalDouble averageOptional = validEntities.stream().mapToDouble(XpGeoQueryEntity::getSeconds).average(); @@ -347,6 +352,8 @@ double waitMinutes = (average * count) / 60; if (waitMinutes > 3) { throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME); }else if(waitMinutes==0){ return 1; } return (int) waitMinutes; } @@ -517,6 +524,16 @@ xpOrder.setQueueName(s); xpOrderClient.updateOrder(xpOrder); // 存储mongodb 数据 XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity(); xpGeoQueryEntity.setOrderId(orderId.toString()); xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat())); // 计算2个时间的秒数 xpGeoQueryEntity.setTime(currentTimeSlot); xpGeoQueryEntity.setStatus(0); xpGeoQueryEntity.setTimestamp(System.currentTimeMillis()); geoQueryEntityService.save(xpGeoQueryEntity); return orderId; } } @@ -525,6 +542,18 @@ redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule())); xpOrder.setQueueName(key); xpOrderClient.updateOrder(xpOrder); // 存储mongodb 数据 XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity(); xpGeoQueryEntity.setOrderId(orderId.toString()); xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat())); // 计算2个时间的秒数 xpGeoQueryEntity.setTime(currentTimeSlot); xpGeoQueryEntity.setStatus(0); geoQueryEntityService.save(xpGeoQueryEntity); return orderId; // xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -1700,17 +1700,8 @@ XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity(); String[] split = popFirstElement.split("_"); xpGeoQueryEntity.setOrderId(split[0]); String[] split1 = split[1].split(","); xpGeoQueryEntity.setLocation(new GeoJsonPoint(Double.parseDouble(split1[0]), Double.parseDouble(split1[1]))); xpGeoQueryEntity.setTimestamp(new Date()); // 计算2个时间的秒数 LocalDateTime createTime = order.getCreateTime(); LocalDateTime acceptanceTime = order.getAcceptanceTime(); xpGeoQueryEntity.setSeconds((int) Duration.between(createTime, acceptanceTime).getSeconds()); String currentTimeSlot = DateUtils.getCurrentTimeSlot(); xpGeoQueryEntity.setTime(currentTimeSlot); // 存mongo数据 xpPricingClient.saveXpGeoQueryEntity(xpGeoQueryEntity); xpPricingClient.updateXpGeoQueryEntity(split[0]); this.updateById(order); }