xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/map/OrderRouteAndFareDto.java
New file @@ -0,0 +1,31 @@ package com.xiaopeng.api.dto.map; import com.xiaopeng.api.dto.operation.LonLatDto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotNull; @Data @ApiModel(description = "订单得线路和运费Dto") public class OrderRouteAndFareDto { @ApiModelProperty(value = "出发地") @NotNull(message = "出发地不能为空") private LonLatDto origin; @ApiModelProperty(value = "目的地") @NotNull(message = "目的地不能为空") private LonLatDto destination; @ApiModelProperty(value = "订单id") @NotNull(message = "订单id不能为空") private Long orderId; @ApiModelProperty(value = "轨迹类型 1=接单轨迹 2=服务轨迹 3=巡游轨迹") @NotNull(message = "轨迹类型不能为空") private Integer routeType; @ApiModelProperty(value = "前端不处理") private Integer routePlanRule; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/VehiclePositionByVinDto.java
New file @@ -0,0 +1,25 @@ package com.xiaopeng.api.dto.operation; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @ApiModel(value = "筛选车辆信息Dto") @AllArgsConstructor @NoArgsConstructor public class VehiclePositionByVinDto { // 围栏id private Long fenceId; // 车辆vin private List<String> vinList; // 数量 private Integer num; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/pushMessage/PushOrderRouteDTO.java
New file @@ -0,0 +1,42 @@ package com.xiaopeng.api.dto.pushMessage; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotNull; import java.io.Serializable; @Data @ApiModel(value = "推送订单轨迹信息") public class PushOrderRouteDTO implements Serializable { @NotNull(message = "订单id不能为空") @ApiModelProperty(value = "订单id") private Long orderId; @NotNull(message = "经度不能为空") @ApiModelProperty(value = "经度") private Double longitude; @NotNull(message = "纬度不能为空") @ApiModelProperty(value = "纬度") private Double latitude; @NotNull(message = "剩余距离不能为空") @ApiModelProperty(value = "剩余距离") private Integer distance; @NotNull(message = "剩余时间不能为空") @ApiModelProperty(value = "剩余时间") private Integer duration; @NotNull(message = "用户id不能为空") @ApiModelProperty(value = "用户id") private Long appUserId; @NotNull(message = "轨迹类型不能为空") @ApiModelProperty(value = "轨迹类型 1=接单轨迹 2=服务轨迹 3=巡游轨迹") private Integer routeType; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/map/XpMapClientFallbackFactory.java
@@ -1,5 +1,6 @@ package com.xiaopeng.api.factory.map; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; @@ -23,6 +24,12 @@ } @Override public R<RouteVo> getOrderDistanceAndDuration(OrderRouteAndFareDto dto) { log.error("获取订单距离和时长失败:{}", cause.getMessage()); return R.fail("获取订单距离和时长失败,"+cause.getMessage()); } @Override public R<Boolean> diagnosisArea(RouteAndFareDto dto) { log.error("判断是否同一经营区域失败:{}", cause.getMessage()); return R.fail("判断是否同一经营区域失败"); xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpPointClientFallbackFactory.java
@@ -64,7 +64,7 @@ } @Override public R queryById(Long id) { public R<XpPoint> queryById(Long id) { log.error("获取点位详情失败:{}", cause.getMessage()); return R.fail("获取点位详情失败"); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/pushMessage/XpPushMessageClientFallbackFactory.java
@@ -1,5 +1,6 @@ package com.xiaopeng.api.factory.pushMessage; import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; @@ -41,6 +42,11 @@ public R<String> sendVehicleLocation(SendMessageDTO dto) { return R.fail("推送车辆实时定位失败,"+cause.getMessage()); } @Override public R<String> pushOrderRoute(PushOrderRouteDTO dto) { return R.fail("通过车辆实时定位推送订单轨迹失败,"+cause.getMessage()); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/vehicleConvoy/XpVehicleClientFallbackFactory.java
@@ -1,7 +1,9 @@ package com.xiaopeng.api.factory.vehicleConvoy; import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.operation.VehiclePositionVo; import com.xiaopeng.common.core.domain.R; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.openfeign.FallbackFactory; @@ -52,6 +54,12 @@ log.error("根据围栏id查询车辆信息失败,原因: {}", cause.getMessage()); return R.ok(new ArrayList<>()); } @Override public R<List<String>> queryVehiclePositionByVin(VehiclePositionByVinDto dto) { log.error("查询车辆信息失败,原因: {}", cause.getMessage()); return R.fail(); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/map/XpMapClient.java
@@ -1,5 +1,6 @@ package com.xiaopeng.api.feignClient.map; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.factory.map.XpMapClientFallbackFactory; import com.xiaopeng.api.factory.operation.XpSystemSettingClientFallbackFactory; @@ -14,7 +15,6 @@ @FeignClient(contextId = "XpMapClient", value = ServiceNameConstantsEnum.XP_MAP_SERVICE, fallbackFactory = XpMapClientFallbackFactory.class) public interface XpMapClient { /** * 获取距离和时长 * @param dto @@ -23,6 +23,14 @@ @PostMapping("/base/v1/mini-program/map/getDistanceAndDuration") R<RouteVo> getDistanceAndDuration(@RequestBody RouteAndFareDto dto); /** * 获取距离和时长 * @param dto * @return */ @PostMapping("/base/v1/mini-program/map/getOrderDistanceAndDuration") R<RouteVo> getOrderDistanceAndDuration(@RequestBody OrderRouteAndFareDto dto); /** * 判断是否同一经营区域 xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpPointClient.java
@@ -52,7 +52,7 @@ * 点位详情 */ @GetMapping("/api/v1/point/queryPointById") public R queryById(@RequestParam Long id); public R<XpPoint> queryById(@RequestParam Long id); /** * 启用/禁用 xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/pushMessage/XpPushMessageClient.java
@@ -1,10 +1,12 @@ package com.xiaopeng.api.feignClient.pushMessage; import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.factory.pushMessage.XpPushMessageClientFallbackFactory; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -45,5 +47,13 @@ */ @PostMapping("/inner/websocket/order/sendVehicleLocation") R<String> sendVehicleLocation(@RequestBody SendMessageDTO dto); /** * 通过车辆实时定位推送订单轨迹 * * @param dto 消息实体 * @return 通过车辆实时定位推送订单轨迹 */ @PostMapping("/inner/v1/order/pushOrderRoute") R<String> pushOrderRoute(@RequestBody PushOrderRouteDTO dto); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/UserVehicleClient.java
@@ -1,15 +1,20 @@ package com.xiaopeng.api.feignClient.vehicleConvoy; import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.factory.vehicleConvoy.UserVehicleClientFallbackFactory; import com.xiaopeng.api.vo.operation.VehiclePositionVo; import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; import com.xiaopeng.api.vo.vehicleConvoy.GetTaxiPassengersVo; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import java.util.List; /** * 小鹏内部用户中心服务 @@ -43,4 +48,6 @@ */ @PostMapping("/logan/vehicleTaxi/update/cancelTaxiPassenger") BaseVehicleUserDto cancelTaxiPassenger(@RequestBody CancelTaxiPassengerVo vo); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/XpVehicleClient.java
@@ -1,7 +1,9 @@ package com.xiaopeng.api.feignClient.vehicleConvoy; import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; import com.xiaopeng.api.factory.vehicleConvoy.XpVehicleClientFallbackFactory; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.operation.VehiclePositionVo; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; import org.springframework.cloud.openfeign.FeignClient; @@ -62,4 +64,11 @@ */ @GetMapping("/inner/vehicle/listByFenceId") R<List<XpVehicle>> listByFenceId(@RequestParam("fenceId") Long fenceId); /** * 查询车辆信息 进行筛选 */ @PostMapping("/inner/vehicle/queryVehiclePositionByVin") R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrderEvaluate.java
@@ -48,5 +48,10 @@ @ApiModelProperty(value = "评价时间") private LocalDateTime evaluateTime; @ApiModelProperty(value = "问题类型id") private Integer feedbackTypeId; @ApiModelProperty(value = "反馈内容") private Integer feedbackContent; @ApiModelProperty(value = "图片 json格式") private Integer feedbackPictures; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/automaticPilot/VehiclePosition.java
@@ -20,7 +20,7 @@ @CompoundIndex(name = "location_index", def = "{'point': '2dsphere'}") } ) public class VehiclePosition implements Serializable { public class VehiclePosition implements Serializable { /** * 车辆id */ xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/VehiclePositionVo.java
File was renamed from xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/VehiclePositionVo.java @@ -1,12 +1,9 @@ package com.xiaopeng.operation.vo; package com.xiaopeng.api.vo.operation; import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.data.mongodb.core.index.CompoundIndex; import org.springframework.data.mongodb.core.index.CompoundIndexes; import org.springframework.data.mongodb.core.mapping.Document; import java.io.Serializable; @@ -25,9 +22,9 @@ */ private String vin; /** * 车辆所属围栏id * 车辆所属区域id */ private Long electronic_id; private Long area_electronic_id; /** * 车辆实时位置信息 */ xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/order/FareBreakdownDetailVo.java
New file @@ -0,0 +1,22 @@ package com.xiaopeng.api.vo.order; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel("订单费用明细详情VO") public class FareBreakdownDetailVo { @ApiModelProperty(value = "type=1 普通时段 type=2 夜间行驶时段 type=3节假日时段") private Integer type; @ApiModelProperty(value = "时段 例:18:00-19:00") private String time; @ApiModelProperty(value = "里程 单位公里") private BigDecimal mileage; @ApiModelProperty(value = "时间") private BigDecimal duration; @ApiModelProperty(value = "金额") private BigDecimal money; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/order/FareBreakdownVo.java
@@ -5,38 +5,27 @@ import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @ApiModel("订单费用明细VO") public class FareBreakdownVo { @ApiModelProperty("起步里程") private Double startMileage; @ApiModelProperty(value = "起步价") private BigDecimal startMoney; @ApiModelProperty(value = "里程公里") private Double mileageKilometers; @ApiModelProperty(value = "里程费") private BigDecimal mileageMoney; @ApiModelProperty(value = "时长分钟") private Double duration; @ApiModelProperty(value = "时长费") private BigDecimal durationMoney; @ApiModelProperty(value = "等待分钟") private Double wait; @ApiModelProperty(value = "等待费") private BigDecimal waitMoney; @ApiModelProperty(value = "远途公里") private Double longDistance; @ApiModelProperty(value = "远途费") private BigDecimal longDistancemoney; @ApiModelProperty("起步价格明细") private List<FareBreakdownDetailVo> start; @ApiModelProperty("里程费价格明细") private List<FareBreakdownDetailVo> mileage; @ApiModelProperty("时长费价格明细") private List<FareBreakdownDetailVo> duration; @ApiModelProperty("远途费价格明细") private List<FareBreakdownDetailVo> longDistance; @ApiModelProperty(value = "红包抵扣金额") private BigDecimal redPacketMoney; @ApiModelProperty(value = "优惠券抵扣金额") private BigDecimal couponMoney; @ApiModelProperty(value = "订单金额") private BigDecimal orderMoney; @ApiModelProperty(value = "订单全程公里数") private BigDecimal totalKilometers; @ApiModelProperty(value = "订单全程时间(单位分钟)") private BigDecimal totalTime; @ApiModelProperty(value = "订单行驶里程") private BigDecimal kilometer; @ApiModelProperty(value = "订单行驶时间") private BigDecimal time; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/order/XpPricingCardVo.java
New file @@ -0,0 +1,47 @@ package com.xiaopeng.api.vo.order; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data @ApiModel(value = "XpPricingCardVo", description = "冒泡页价格卡片") public class XpPricingCardVo { @ApiModelProperty(value = "价格总额") private Double totalPrice=0.0; @ApiModelProperty(value = "起步价格") private Double startPrice; @ApiModelProperty(value = "时间段") private String time; @ApiModelProperty(value = "距离") private Double distance; @ApiModelProperty(value = "时长") private Double duration; @ApiModelProperty(value = "里程费") private Double distancePrice; @ApiModelProperty(value = "普通时段公里数") private Double distancePriceNormal; @ApiModelProperty(value = "时长费") private Double durationPrice; @ApiModelProperty(value = "普通时段时长数") private Double durationPriceNormal; @ApiModelProperty(value = "优惠券") private String coupon; } xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/constant/CacheConstants.java
@@ -115,4 +115,16 @@ * 附近点位距离 */ public static final String NEAR_POINT_DISTANCE = "NEAR_POINT_DISTANCE"; /** * 订单车辆位置 */ public static final String ORDER_OLD_LOCATION = "order_old_location:"; /** * 订单车辆轨迹 */ public static final String ORDER_ROUTE = "order_route:"; /** * 订单车辆轨迹,禁止用于其他用处 */ public static final String ORDER_ROUTE_CAPTURE = "order_route_capture:"; } xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/PushMessageTypeEnum.java
@@ -11,6 +11,7 @@ ORDER_STATUS("ORDER_STATUS"), VEHICLE_LOCATION("VEHICLE_LOCATION"), ORDER_ROUTE("ORDER_ROUTE"); @Getter xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/web/domain/MongoBaseModel.java
New file @@ -0,0 +1,16 @@ package com.xiaopeng.common.core.web.domain; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.util.Date; /** * @author zhibing.pu * @Date 2024/8/26 19:05 */ @Data public class MongoBaseModel { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date createTime = new Date(); } xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/web/service/BaseService.java
File was renamed from xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/mangodb/base/BaseService.java @@ -1,4 +1,4 @@ package com.xiaopeng.map.mangodb.base; package com.xiaopeng.common.core.web.service; import java.util.List; xp-robotaxi-common/xp-common-redis/src/main/java/com/xiaopeng/common/redis/service/RedisService.java
@@ -173,8 +173,9 @@ } // 获取第一个元素但不删除 public Object getFirstElement(String key) { return redisTemplate.opsForList().index(key, 0); public String getFirstElement(String key) { String index = (String) redisTemplate.opsForList().index(key, 0); return index; } // 获取第一个元素并删除(弹出) @@ -374,7 +375,7 @@ */ public Set<String> getQuoteMatchName(String name) { // 模糊查询key为name的值 Set<String> keys = redisTemplate.keys("*" + name ); Set<String> keys = redisTemplate.keys(name + "*"); return keys; } } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
@@ -1,11 +1,14 @@ package com.xiaopeng.map.controller; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.vo.map.XpDistanceAndDurationVo; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.map.mangodb.model.GeoPoint; import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService; import com.xiaopeng.map.utils.GDMapGeocodingUtil; @@ -13,6 +16,7 @@ import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -31,10 +35,12 @@ private final GDMapGeocodingUtil gdMapGeocodingUtil; private final XpGeoFencingPolygonService xpGeoFencingPolygonService; private final RedisService redisService; public XpMapController(GDMapGeocodingUtil gdMapGeocodingUtil, XpGeoFencingPolygonService xpGeoFencingPolygonService) { public XpMapController(GDMapGeocodingUtil gdMapGeocodingUtil, XpGeoFencingPolygonService xpGeoFencingPolygonService, RedisService redisService) { this.gdMapGeocodingUtil = gdMapGeocodingUtil; this.xpGeoFencingPolygonService = xpGeoFencingPolygonService; this.redisService = redisService; } @@ -72,5 +78,45 @@ } /** * 获取订单距离和时长 * @param dto * @return */ @PostMapping("/map/getOrderDistanceAndDuration") public R<RouteVo> getOrderDistanceAndDuration(@Validated @RequestBody OrderRouteAndFareDto dto){ // 获取电子围栏的禁行区域点位 GeoPoint startPoint = new GeoPoint(dto.getOrigin().getLongitude(),dto.getOrigin().getLatitude()); List<String> operatingArea = xpGeoFencingPolygonService.findFencesContainingPoint(startPoint, "operating_area", "points"); String fenceId = operatingArea.get(0); List<Document> pointsInFence = xpGeoFencingPolygonService.findPointsByParentId(fenceId, "parentId", "prohibited_area"); // 避让区域 ArrayList<String> pointStrParam = new ArrayList<>(); for (Document document : pointsInFence) { List<GeoPoint> points = document.getList("points", GeoPoint.class); // 一个区域的点位 ArrayList<String> pointStr = new ArrayList<>(); for (GeoPoint point : points) { pointStr.add( point.getLongitude()+","+point.getLatitude()); } if(!pointStr.isEmpty()){ pointStrParam.add(String.join(";", pointStr)); } } RouteVo routeVo = gdMapGeocodingUtil.getDistanceAndTime(dto.getOrigin(), dto.getDestination(), String.join("|", pointStrParam), fenceId,dto.getRoutePlanRule()); if(routeVo==null){ return R.fail("没有找到路线"); } // 存储redis redisService.setCacheObject(CacheConstants.ORDER_ROUTE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); // 存储路线偏离缓存,后续进行轨迹截取 redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); return R.ok(routeVo); } } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/mangodb/service/XpGeoFencingPolygonService.java
@@ -1,7 +1,7 @@ package com.xiaopeng.map.mangodb.service; import com.xiaopeng.api.model.map.XpGeoFencingPolygon; import com.xiaopeng.map.mangodb.base.BaseService; import com.xiaopeng.common.core.web.service.BaseService; import com.xiaopeng.map.mangodb.model.GeoPoint; import org.bson.Document; import org.springframework.stereotype.Repository; xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/GDMapGeocodingUtil.java
@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.common.core.utils.HttpUtils; import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService; import com.xiaopeng.map.utils.mangoUtils.MongoGeoFenceUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -54,11 +55,15 @@ params.put("start", start.getLongitude() + "," + start.getLatitude()); params.put("end", end.getLongitude() + "," + end.getLatitude()); params.put("routeUserType",2); params.put("voidPolygons", avoidRoads); if(avoidRoads!=null && !avoidRoads.isEmpty()){ params.put("voidPolygons", avoidRoads); } if(routePlanRule!=null){ params.put("strategy", routePlanRule); } String post = HttpUtils.post(url, JSON.toJSONString(params)); System.out.println("高德地图返回结果:"+ post); String forObject = restTemplate.getForObject(url, String.class, params); JSONObject jsonObject = JSON.parseObject(forObject); String data = jsonObject.getString("data"); xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPointManagementController.java
@@ -86,7 +86,7 @@ */ @GetMapping("/queryPointById") @ApiOperation(value = "点位详情") public R queryById(@RequestParam Long id) { public R<XpPoint> queryById(@RequestParam Long id) { return R.ok(xpPointService.getById(id)); } /** xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -396,11 +396,11 @@ // 获取起步里程 XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, dto.getOpenCityId())); Integer startMileage = XpPricingUtil.getStartMileage(xpPricing.getStartingFareJson()); if (startMileage == null) { throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); } // XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, dto.getOpenCityId())); // Integer startMileage = XpPricingUtil.getStartMileage(xpPricing.getStartingFareJson()); // if (startMileage == null) { // throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); // } // 根据id获取手机号 @@ -417,7 +417,7 @@ // 生成订单数据 XpOrder xpOrder = new XpOrder(); xpOrder.setStartMileage(Double.valueOf(startMileage)); // xpOrder.setStartMileage(Double.valueOf(startMileage)); xpOrder.setAppUserId(Long.valueOf(uid)); xpOrder.setOrderNumber("XP" + System.currentTimeMillis()); @@ -473,10 +473,10 @@ Integer distance = 0; Integer duration = 0; if (distanceAndDuration.getCode() != 200) { throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); // throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); } distance = distanceAndDuration.getData().getDistance(); duration = distanceAndDuration.getData().getDuration(); // distance = distanceAndDuration.getData().getDistance(); // duration = distanceAndDuration.getData().getDuration(); // 产生订单 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -3,10 +3,14 @@ import cn.hutool.core.bean.BeanUtil; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.VehicleControlClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.operation.XpElectronicFence; import com.xiaopeng.api.model.operation.XpTradingStrategy; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; @@ -15,18 +19,15 @@ import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.operation.mapper.XpElectronicFenceMapper; import com.xiaopeng.operation.service.IXpElectronicFenceAreaService; import com.xiaopeng.operation.service.IXpTradingStrategyService; import com.xiaopeng.operation.service.XpPointService; import com.xiaopeng.operation.utils.mango.VehiclePositionService; import com.xiaopeng.operation.utils.map.FastDistanceCalculator; import com.xiaopeng.operation.vo.RouterVo; import com.xiaopeng.operation.vo.VehiclePositionVo; import org.redisson.Redisson; import com.xiaopeng.api.vo.operation.VehiclePositionVo; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; @@ -62,6 +63,9 @@ private UserVehicleClient userVehicleClient; @Autowired private XpVehicleClient xpVehicleClient; @Autowired private RedissonClient redissonClient; @Autowired @@ -80,21 +84,24 @@ threadPoolTaskExecutor.initialize(); } @Autowired private XpElectronicFenceMapper xpElectronicFenceMapper; /** * 5秒执行一次 */ // @Scheduled(cron = "0/5 * * * * ?") @Scheduled(cron = "0/5 * * * * ?") public void taskOrder() { System.out.println("5秒执行一次"); Set<String> quoteMatchName = redisService.getQuoteMatchName(CacheConstants.QUEUE_POINT_ID); for (String name : quoteMatchName) { Object firstElement = redisService.getFirstElement(name); String firstElement = redisService.getFirstElement(name); if (firstElement != null) { String[] split = firstElement.toString().split("_"); // 如果市未处理 创建新任务 if (split[2].equals("0")) { // 状态改为处理中 redisService.updateFirst(name, split[0] + "_" + split[1] + "_1"); // redisService.updateFirst(name, split[0] + "_" + split[1] + "_1"+split[3]+split[4]+split[5]+split[6]); threadPoolTaskExecutor.submit(() -> { orderProcess(name, firstElement.toString()); }); @@ -110,6 +117,7 @@ * @param firstElement 队列第一个元素 */ private void orderProcess(String quoteName, String firstElement) { System.out.println("进入处理环节"); XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null); String orderId = firstElement.split("_")[0]; String lonLat = firstElement.split("_")[1]; @@ -190,7 +198,7 @@ processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); // 最终没找到车 redisService.popFirstElement(quoteName); // redisService.popFirstElement(quoteName); // 取消订单 xpOrderClient.cancelOrder(orderId); @@ -207,6 +215,7 @@ * @param xpTradingStrategy 规则 */ private void processPushOrder(String quoteName, int count, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) { System.out.println("进入推单环环节"); // 订单状态 R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); if (xpOrderR.getCode() != 200) { @@ -215,12 +224,39 @@ if (xpOrderR.getData().getStatus() != 1) { return; } XpOrder xpOrder = xpOrderR.getData(); // 找出围栏id Long xpElectronicFenceAreaId = xpOrder.getXpElectronicFenceAreaId(); XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceAreaId); for (int i = 0; i < count; i++) { System.out.println("进入找车环节"); // 根据距离找车 // 车多则根据配置找具体车数量 根据距离最近 // 更改 暂不限制数量 List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(Double.parseDouble(split[0]), Double.parseDouble(split[1]), xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount()); // 获取车辆的区域信息 if(positionList.isEmpty()){ continue; } List<String> vinList = positionList.stream().map(VehiclePosition::getVin).collect(Collectors.toList()); // 获取车辆的信息 筛选出可用车辆 R<List<String>> vehiclePositionVos = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(xpElectronicFence.getId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount())); if(vehiclePositionVos.getCode()!=200){ continue; } List<VehiclePositionVo> availableVehiclesNearby = BeanUtil.copyToList(positionList, VehiclePositionVo.class); List<String> data = vehiclePositionVos.getData(); // 找出符合条件的 availableVehiclesNearby = availableVehiclesNearby.stream().filter(e->data.contains(e.getVin())).collect(Collectors.toList()); // List<VehiclePositionVo> availableVehiclesNearby =vehiclePositionVos.getData(); if (!availableVehiclesNearby.isEmpty()) { if (availableVehiclesNearby.size() > 1) { @@ -584,6 +620,9 @@ addTaxiPassengerVo.setOrderNo(orderNo); // TODO appid addTaxiPassengerVo.setAppId(""); BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo); if (baseVehicleUserDto.getCode() == 200) { xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/XpPricingUtil.java
@@ -357,6 +357,300 @@ return xpPricingCardVo; } /** * 行程结束后计算费用 * @param rule 基础规则 * @param distance 里程 * @param duration 时间 * @param wait 时间 * @param waitMoney 等待费 * @param openCityId 开通城市id * @param isDynamicPriceStatus 是否开启动态调价 * @return * @throws Exception */ // public XpPricingCardVo calculationFinalPrice(String uid,JSONObject rule, JSONArray startingFareJson, double distance, long duration, long wait, Double waitMoney,Integer isDynamicPriceStatus,Long openCityId,String dynamicPricingJson) { // // // // 默认费率1 // double priceRate=1; // if(isDynamicPriceStatus==1){ // // 先判断是否已经调价过了 // Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid); // if(userDynamicPriceObj!=null){ // // 是否调价过了 // priceRate = Double.parseDouble(userDynamicPriceObj.toString()); // }else { // // 没有调过 // //是否触发动态调价 redis获取 // Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + openCityId); // if(dynamicPriceObj!=null){ // JSONObject jsonObject = JSONObject.parseObject(dynamicPricingJson); // // 触发动态调价 // // value=时间 // String timeStr = dynamicPriceObj.toString(); // // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率 // R<Integer> r = xpOrderClient.getOrderNum(timeStr); // if(r.getData()==200){ // int num = r.getData(); // // X单上升一次调价 // Integer orderNum = getOrderNum(jsonObject, 4); // // 需要调价的次数 // int count = num / orderNum; // if(count>0){ // // 计算每次上升的费率 // Integer upRate = getOrderNum(jsonObject, 5); // BigDecimal divide = new BigDecimal(upRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); // for (int i = count; i > 0; i--) { // // 当前费率+(费率*上升百分比) // priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); // } // // // 冷却时间 // Integer time = getOrderNum(jsonObject, 6); // // 触发调价了 // redisService.setCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid, priceRate,time.longValue(), TimeUnit.MINUTES); // } // } // // } // } // // } // // // // XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); // double amount = 0; // //等待费 // Date date = new Date(); // // 计算出是在那个时间段内 // for (Object o : startingFareJson) { // JSONObject startingFare = (JSONObject) o; // Calendar calendarStart = Calendar.getInstance(); // calendarStart.setTime(date); // calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num1").split(":")[0])); // calendarStart.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num1").split(":")[1])); // // Calendar calendarEnd = Calendar.getInstance(); // calendarEnd.setTime(date); // calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num2").split(":")[0])); // calendarEnd.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num2").split(":")[1])); // // 找到符合条件的直接跳出循环 // if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { // rule.put("num1", startingFare.get("num3")); // rule.put("num2", startingFare.get("num4")); // rule.put("num3", startingFare.get("num5")); // rule.put("num4", startingFare.get("num6")); // rule.put("num5", startingFare.get("num7")); // // rule.put("startTime", startingFare.getString("num1")); // rule.put("endTime", startingFare.getString("num2")); // break; // } // } // // // double realDistance = distance / 1000;//实际公里 // double realTime = duration / 60;//实际时间 // double exceedDistance = (realDistance - rule.getDouble("num2")) < 0 ? 0 : realDistance - rule.getDouble("num2");//超出起步里程的公里 // double exceedTime = (realTime - rule.getDouble("num3")) < 0 ? 0 : realTime - rule.getDouble("num3");//超过起步分钟数的时间 // double longDistanceOne = 0;//远途1段 // double longDistanceTwo = 0;//远途2段 // double longDistanceThree = 0;//远途3段 // // // //夜间服务处理逻辑 // Calendar calendarNight = Calendar.getInstance(); // calendarNight.setTime(date); // calendarNight.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[0])); // calendarNight.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[1])); // // Calendar calendar = Calendar.getInstance(); // calendar.setTime(date); // calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[0])); // calendar.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[1])); // // // 先判断今日是否节假日 // boolean holiday = holidayUtil.isHoliday(); // if (holiday) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num32") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num33") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num34") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num29") + (exceedDistance * rule.getDouble("num30")) + (exceedTime * rule.getDouble("num31")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num29")); // // 时间段 // xpPricingCardVo.setTime("节假日"); // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num30")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num31"))); // // // } else { // if (date.getTime() > calendarNight.getTimeInMillis() && date.getTime() < calendar.getTimeInMillis()) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num18") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num19") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num20") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num15") + (exceedDistance * rule.getDouble("num16")) + (exceedTime * rule.getDouble("num17")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num15")); // // 时间段 // xpPricingCardVo.setTime(rule.getString("num14")); // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num16")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num17"))); // // // } else { // // // 高峰处理 // Calendar calendarStart = Calendar.getInstance(); // calendarStart.setTime(date); // calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[0])); // calendarStart.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[1])); // // Calendar calendarEnd = Calendar.getInstance(); // calendarEnd.setTime(date); // calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[0])); // calendarEnd.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[1])); // // Calendar s2 = Calendar.getInstance(); // s2.setTime(date); // s2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[0])); // s2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[1])); // // Calendar e2 = Calendar.getInstance(); // e2.setTime(date); // e2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[0])); // e2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[1])); // //高峰时段处理逻辑 // if ((date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) || (date.getTime() > s2.getTimeInMillis() && date.getTime() < e2.getTimeInMillis())) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num26") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num27") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num28") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num23") + (exceedDistance * rule.getDouble("num24")) + (exceedTime * rule.getDouble("num25")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num23")); // // 时间段 // if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { // xpPricingCardVo.setTime(rule.getString("num21")); // } else { // xpPricingCardVo.setTime(rule.getString("num22")); // } // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num24")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num25"))); // // } else { // //其他时间段的计算 // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num8") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num11") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num13") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num1") + (exceedDistance * rule.getDouble("num4")) + (exceedTime * rule.getDouble("num5")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num1")); // // 时间段 // xpPricingCardVo.setTime(rule.getString("startTime") + " - " + rule.getString("endTime")); // // xpPricingCardVo.setDistancePriceNormal(rule.getDouble("num2")); // // xpPricingCardVo.setDurationPriceNormal(rule.getDouble("num3")); // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num4")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num5"))); // // } // } // } // // // 订单总额 // Double startPrice = xpPricingCardVo.getStartPrice(); // // 先减去起步价重新计算 // amount = amount - startPrice; // // 动态计算费用 // startPrice= new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); // amount = amount+startPrice; // xpPricingCardVo.setTotalPrice(amount); // // // return xpPricingCardVo; // } /** xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/mango/VehiclePositionService.java
@@ -40,13 +40,13 @@ .near(referencePoint) .maxDistance(distanceInMeters)); query.addCriteria(Criteria.where("status").is(1)); // 运营中 query.addCriteria(Criteria.where("state").is(1)); // 接单中 query.addCriteria(Criteria.where("state").is(0)); // 空闲中 // 可以添加排序,按距离排序 query.with(Sort.by(Sort.Direction.ASC, "point")); // 可以限制返回数量 query.limit(num); // // 可以限制返回数量 // query.limit(num); return mongoTemplate.find(query, VehiclePosition.class); } @@ -63,4 +63,21 @@ return mongoTemplate.findOne(query, VehiclePosition.class); } /** * 所有的车辆 */ public List<VehiclePosition> findAll() { // 构建查询条件 Query query = new Query(); query.addCriteria(Criteria.where("status").is(1)); // 运营中 query.addCriteria(Criteria.where("state").is(1)); // 接单中 // 可以添加排序,按距离排序 query.with(Sort.by(Sort.Direction.ASC, "point")); return mongoTemplate.find(query, VehiclePosition.class); } } xp-robotaxi-order-boot/pom.xml
@@ -15,14 +15,14 @@ </description> <dependencies> <!-- <dependency>--> <!-- <groupId>com.alibaba.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>com.alibaba.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> @@ -120,21 +120,23 @@ </dependency> <dependency> <groupId>com.xiaopeng.logan</groupId> <artifactId>logan-starter-core</artifactId> <version>2.3.5</version> </dependency> <dependency> <groupId>com.xiaopeng.logan</groupId> <artifactId>logan-commons-legacy</artifactId> <version>2.3.5</version> </dependency> <dependency> <groupId>com.xiaopeng.logan</groupId> <artifactId>logan2-namor-client</artifactId> <version>1.16.0</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.xiaopeng.logan</groupId>--> <!-- <artifactId>logan-starter-core</artifactId>--> <!-- <version>2.3.5</version>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>com.xiaopeng.logan</groupId>--> <!-- <artifactId>logan-commons-legacy</artifactId>--> <!-- <version>2.3.5</version>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>com.xiaopeng.logan</groupId>--> <!-- <artifactId>logan2-namor-client</artifactId>--> <!-- <version>1.16.0</version>--> <!-- </dependency>--> </dependencies> <build> xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -16,6 +16,7 @@ import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.WebUtils; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.exportExcel.XpOrderExportExcel; @@ -366,6 +367,7 @@ String uid = request.getHeader("XP-Uid"); return xpOrderService.payment(dto,uid); } /** * 订单评价 */ @@ -382,8 +384,8 @@ /** * 订单状态修改-车控消息推送我方调用(内部接口) */ @PostMapping("/inner/v1/order/updateOrderStatus") @ApiOperation(value = "订单状态推送修改") @PostMapping("/inner/v1/order/updateOrderStatus") public R<String> updateOrderStatus(@RequestParam Long orderId, @RequestParam Integer status) { return xpOrderService.updateOrderStatus(orderId,status); @@ -393,10 +395,21 @@ * 业务流程-通过订单id查询车辆信息 */ @ApiOperation(value = "通过订单id查询车辆信息", tags = {"小程序-业务流程"}) @GetMapping("/api/v1/order/queryVehicleByOrderId") @XpClientCheck(checkToken = false, checkOtpToken = true) @GetMapping("/api/v1/mini-program/order/queryVehicleByOrderId") public R<XpVehicle> queryVehicleByOrderId(@RequestParam Long orderId, HttpServletRequest request) { String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.queryVehicleByOrderId(orderId,uid)); } /** * 订单车辆定位实时存储-订单车辆定位实时存储(内部接口) */ @ApiOperation(value = "订单车辆定位实时存储") @PostMapping("/inner/v1/order/saveVehicleLocation") public R<String> saveVehicleLocation(@RequestBody OrderTrajectory orderTrajectory) { xpOrderService.saveVehicleLocation(orderTrajectory); return R.ok(); } } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mangodb/model/OrderTrajectory.java
New file @@ -0,0 +1,47 @@ package com.xiaopeng.order.mangodb.model; import com.xiaopeng.common.core.web.domain.MongoBaseModel; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.data.mongodb.core.mapping.Document; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @Document(collection = "order_trajectory") //指定要对应的文档名(表名) @Accessors(chain = true) public class OrderTrajectory extends MongoBaseModel { /** * 订单id */ private Long orderId; /** * 经纬度 坐标 (104.45645456,34.41564654) */ private String location; /** * 方向角(0-359°) */ private Integer direction; /** * 速度 */ private Double speed; /** * 时间戳 毫秒 */ private Long locatetime; /** * 距离 米 */ private Double distance; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mangodb/service/OrderTrajectoryService.java
New file @@ -0,0 +1,15 @@ package com.xiaopeng.order.mangodb.service; import com.xiaopeng.common.core.web.service.BaseService; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import org.springframework.stereotype.Repository; /** * MongoDB Repository for XpGeoFencingPolygon * @author zhibing.pu * @date 2023/4/29 23:53 */ @Repository public interface OrderTrajectoryService extends BaseService<OrderTrajectory> { } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mangodb/service/impl/OrderTrajectoryServiceImpl.java
New file @@ -0,0 +1,33 @@ package com.xiaopeng.order.mangodb.service.impl; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.mangodb.service.OrderTrajectoryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.stereotype.Service; import java.util.List; @Service public class OrderTrajectoryServiceImpl implements OrderTrajectoryService { @Autowired private MongoTemplate mongoTemplate; @Override public int create(OrderTrajectory orderTrajectory) { mongoTemplate.insert(orderTrajectory); return 1; } @Override public OrderTrajectory findById(String id) { return mongoTemplate.findById(id, OrderTrajectory.class); } @Override public List<OrderTrajectory> findAll() { return mongoTemplate.findAll(OrderTrajectory.class); } } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/dto/XpOrderCommentDto.java
@@ -11,4 +11,10 @@ @ApiModelProperty(value = "订单评分") private Integer orderRating; @ApiModelProperty(value = "问题类型id") private Integer feedbackTypeId; @ApiModelProperty(value = "反馈内容") private Integer feedbackContent; @ApiModelProperty(value = "图片 json格式") private Integer feedbackPictures; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/dto/XpOrderPayDto.java
@@ -8,7 +8,4 @@ @ApiModel(value = "订单发起支付参数") public class XpOrderPayDto { private Long orderId; @ApiModelProperty(value = "用户所选优惠券") private Long couponId; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
@@ -13,6 +13,7 @@ import com.xiaopeng.api.vo.order.XpPointInfoVo; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; @@ -180,4 +181,9 @@ */ Integer getOrderNum(GetOrderNumDto dto); /** * 保存车辆位置信息 * @param orderTrajectory */ void saveVehicleLocation(OrderTrajectory orderTrajectory); } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -26,6 +26,7 @@ import com.xiaopeng.api.feignClient.operation.XpPointClient; import com.xiaopeng.api.feignClient.operation.XpPricingClient; import com.xiaopeng.api.model.account.XpAppUser; import com.xiaopeng.api.model.operation.XpPoint; import com.xiaopeng.api.model.operation.XpPricing; import com.xiaopeng.api.model.vehicleConvoy.XpFleet; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; @@ -34,14 +35,13 @@ import com.xiaopeng.api.model.order.XpOrderEvaluate; import com.xiaopeng.api.model.order.XpOrderReassign; import com.xiaopeng.api.vo.account.UserCouponVo; import com.xiaopeng.api.vo.order.FareBreakdownVo; import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; import com.xiaopeng.api.vo.order.XpPointInfoVo; import com.xiaopeng.api.vo.order.*; import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.core.utils.GeodesyUtil; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.core.web.domain.BaseModel; import com.xiaopeng.common.core.web.page.PageInfo; @@ -49,6 +49,9 @@ import com.xiaopeng.common.security.utils.SecurityUtils; import com.xiaopeng.order.constant.I18nKeyConstant; import com.xiaopeng.order.job.jobs.EndTripJob; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.mangodb.service.OrderTrajectoryService; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.mapper.XpOrderMapper; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; @@ -66,7 +69,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -107,6 +115,12 @@ private final RedisService redisService; private final XpPricingClient xpPricingClient; private final XpSystemSettingClient xpSystemSettingClient; private final OrderTrajectoryService orderTrajectoryService; @Autowired private MongoTemplate mongoTemplate; // @Autowired // private XpPricingUtil xpPricingUtil; @Override public OrderStatisticsDTO getOrderStatistics(StatisticsQueryDTO query) { @@ -769,6 +783,9 @@ evaluate.setAppUserId(Long.valueOf(uid)); evaluate.setOrderRating(dto.getOrderRating()); evaluate.setEvaluateTime(LocalDateTime.now()); evaluate.setFeedbackContent(dto.getFeedbackContent()); evaluate.setFeedbackPictures(dto.getFeedbackPictures()); evaluate.setFeedbackTypeId(dto.getFeedbackTypeId()); xpOrderEvaluateService.save(evaluate); } @@ -785,7 +802,10 @@ xpOrder.setStatus(status); switch (status) { case 4: // 添加取消订单定时任务job // 查询起点点位 Long startPointId = xpOrder.getStartPointId(); XpPoint xpPoint = xpPointClient.queryById(startPointId).getData(); // 添加取消订单定时任务job 时间为点位限停时长 Map<String, ? extends Object> cancelJobMaps = new ImmutableMap.Builder<String, Long>(). put("id", xpOrder.getId()) @@ -794,7 +814,7 @@ OrderCancelJob.class, (OrderCancelJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ORDER_CANCEL, DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(5)), DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(xpPoint.getParkingTimeLimit())), cancelJobMaps ); // 车辆到达上车点时间 @@ -847,39 +867,70 @@ if (pricing == null) { throw new ServiceException("当前城市未配置定价规则", I18nKeyConstant.ORDER_PRICING_NOT_EXISTS); } Long id = pricing.getId(); Integer pricingType = pricing.getPricingType(); String basicPricingJson = pricing.getBasicPricingJson(); String startingFareJson = pricing.getStartingFareJson(); String dynamicPricingJson = pricing.getDynamicPricingJson(); String priceRule = pricing.getPriceRule(); // 根据计价规则计算费用 BigDecimal startMoney = BigDecimal.ZERO;// 起步价 BigDecimal mileageMoney = BigDecimal.ZERO;// 里程费 BigDecimal durationMoney = BigDecimal.ZERO;// 时长费 BigDecimal waitMoney = BigDecimal.ZERO;// 等待费 BigDecimal longDistancemoney = BigDecimal.ZERO;// 远途费 BigDecimal redPacketMoney = BigDecimal.ZERO;// 红包抵扣金额 BigDecimal couponMoney = BigDecimal.ZERO;// 优惠券抵扣金额 if (pricingType == 1) { } else { // 查询订单轨迹 List<OrderTrajectory> trajectories = mongoTemplate.find( new Query(Criteria.where("orderId").is(orderId)) .with(Sort.by(Sort.Direction.ASC, "locatetime")), OrderTrajectory.class ); // 计算等待时间 LocalDateTime boardingTime = order.getBoardingTime();// 上车时间 LocalDateTime arrivalTime = order.getArrivalTime();// 车辆到达上车点时间 // 行程开始时间 Integer waitTime =Math.abs( (int) Duration.between(boardingTime, arrivalTime).getSeconds()); // 计算订单总行驶距离,单位米 Double totalDistance = 0.00D; // 行程总时间 秒 LocalDateTime tripBegin = order.getTripBegin(); LocalDateTime tripEnd = order.getTripEnd(); long seconds = Duration.between(tripBegin, tripEnd).getSeconds(); for (OrderTrajectory trajectory : trajectories) { } if (org.springframework.util.StringUtils.hasLength(basicPricingJson)) { // XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationPrice( // order.getAppUserId().toString(),JSON.parseObject(pricing.getBasicPricingJson()), // JSON.parseArray(pricing.getStartingFareJson()), // pricing.getDynamicPricingJson(), // pricing.getIsDynamicPrice(), // totalDistance, // seconds, // order.getCityId() // ); } if (org.springframework.util.StringUtils.hasLength(startingFareJson)) { // Long id = pricing.getId(); // Integer pricingType = pricing.getPricingType(); // String basicPricingJson = pricing.getBasicPricingJson(); // String startingFareJson = pricing.getStartingFareJson(); // String dynamicPricingJson = pricing.getDynamicPricingJson(); // String priceRule = pricing.getPriceRule(); // // 根据计价规则计算费用 // BigDecimal startMoney = BigDecimal.ZERO;// 起步价 // BigDecimal mileageMoney = BigDecimal.ZERO;// 里程费 // BigDecimal durationMoney = BigDecimal.ZERO;// 时长费 // BigDecimal waitMoney = BigDecimal.ZERO;// 等待费 // BigDecimal longDistancemoney = BigDecimal.ZERO;// 远途费 // BigDecimal redPacketMoney = BigDecimal.ZERO;// 红包抵扣金额 // BigDecimal couponMoney = BigDecimal.ZERO;// 优惠券抵扣金额 // if (pricingType == 1) { // // } else { // // } // if (org.springframework.util.StringUtils.hasLength(basicPricingJson)) { // // } // if (org.springframework.util.StringUtils.hasLength(startingFareJson)) { // // } // if (org.springframework.util.StringUtils.hasLength(dynamicPricingJson)) { // // } // if (org.springframework.util.StringUtils.hasLength(priceRule)) { // // } } if (org.springframework.util.StringUtils.hasLength(dynamicPricingJson)) { } if (org.springframework.util.StringUtils.hasLength(priceRule)) { } // 计算完价格后 挑选优惠券 GetUserCouponDto getUserCouponDto = new GetUserCouponDto(); // 计算完价格后 挑选优惠券 GetUserCouponDto getUserCouponDto = new GetUserCouponDto(); getUserCouponDto.setUserId(Long.valueOf(uid)); getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue()); R<UserCouponVo> userCouponVoR = xpAppUserCouponClient.getUserCoupon(getUserCouponDto); @@ -907,23 +958,43 @@ @Override public R<FareBreakdownVo> fareBreakdown(Long orderId, String uid) { XpOrder order = this.getById(orderId); FareBreakdownVo fareBreakdownVo = new FareBreakdownVo(); BeanUtils.copyProperties(order, fareBreakdownVo); fareBreakdownVo.setTotalKilometers( BigDecimal.valueOf(order.getStartMileage() + order.getMileageKilometers() + order.getLongDistance()) // 查询订单轨迹 List<OrderTrajectory> trajectories = mongoTemplate.find( new Query(Criteria.where("orderId").is(orderId)) .with(Sort.by(Sort.Direction.ASC, "locatetime")), OrderTrajectory.class ); LocalDateTime createTime = order.getCreateTime(); LocalDateTime tripEnd = order.getTripEnd(); // 计算行程时间 单位分钟 // 计算订单总行驶距离,单位米 Double totalDistance = 0.00D; for (OrderTrajectory trajectory : trajectories) { // 计算时间差 Duration duration = Duration.between(createTime, tripEnd); // 转换为分钟并保留一位小数 BigDecimal minutes = BigDecimal.valueOf(duration.getSeconds()) .divide(BigDecimal.valueOf(60), 1, RoundingMode.HALF_UP); } FareBreakdownVo fareBreakdownVo = new FareBreakdownVo(); // fareBreakdownVo.setStart(); // fareBreakdownVo.setMileage(); // fareBreakdownVo.setDuration(); // fareBreakdownVo.setLongDistance(); // fareBreakdownVo.setRedPacketMoney(); // fareBreakdownVo.setCouponMoney(); // fareBreakdownVo.setOrderMoney(); fareBreakdownVo.setTotalTime(minutes); // BeanUtils.copyProperties(order, fareBreakdownVo); // fareBreakdownVo.setTotalKilometers( // BigDecimal.valueOf(order.getStartMileage() + order.getMileageKilometers() + order.getLongDistance()) // ); // LocalDateTime createTime = order.getCreateTime(); // LocalDateTime tripEnd = order.getTripEnd(); // // 计算行程时间 单位分钟 // // // 计算时间差 // Duration duration = Duration.between(createTime, tripEnd); // // // 转换为分钟并保留一位小数 // BigDecimal minutes = BigDecimal.valueOf(duration.getSeconds()) // .divide(BigDecimal.valueOf(60), 1, RoundingMode.HALF_UP); // // fareBreakdownVo.setTotalTime(minutes); return R.ok(fareBreakdownVo); } @@ -938,6 +1009,7 @@ /** * 添加订单 * * @param xpOrder * @return */ @@ -960,6 +1032,7 @@ /** * 获取订单数量 * * @param dto * @return */ @@ -969,6 +1042,41 @@ return num.intValue(); } @Override public void saveVehicleLocation(OrderTrajectory orderTrajectory) { // 查询订单信息 XpOrder xpOrder = this.getById(orderTrajectory.getOrderId()); // 计算距离 // 获取上一次定位 String oldLocation = redisService.getCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId()); if(StringUtils.isEmpty(oldLocation)){ // 首次定位 xpOrder.setMileageKilometers(0D); this.updateById(xpOrder); orderTrajectory.setDistance(0D); // 存储mongo数据 orderTrajectoryService.create(orderTrajectory); // 存储首次定位 redisService.setCacheObject(CacheConstants.ORDER_OLD_LOCATION + orderTrajectory.getOrderId(), orderTrajectory.getLocation()); }else { Map<String, Double> distance = GeodesyUtil.getDistance(orderTrajectory.getLocation(), oldLocation); if(null != distance){ Double distance1 = distance.get("WGS84"); if(distance1 > 50 && xpOrder.getStatus() == 6){//大于50米表示在移动,且在服务中的时候记录里程 xpOrder.setMileageKilometers(BigDecimal.valueOf(xpOrder.getMileageKilometers()).add(new BigDecimal(distance1)).setScale(2, RoundingMode.HALF_EVEN).doubleValue()); this.updateById(xpOrder); // 存储本次距离 orderTrajectory.setDistance(distance1); // 存储mongo数据 orderTrajectoryService.create(orderTrajectory); } }else{ log.error("调用高德计算距离出错"); } } } /** * 获取当前用户正在执行的订单 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/XpPricingUtil.java
New file @@ -0,0 +1,667 @@ //package com.xiaopeng.order.utils; // //import com.alibaba.fastjson.JSONArray; //import com.alibaba.fastjson.JSONObject; //import com.xiaopeng.api.dto.order.GetOrderNumDto; //import com.xiaopeng.api.feignClient.order.XpOrderClient; //import com.xiaopeng.api.vo.order.XpPricingCardVo; //import com.xiaopeng.common.core.domain.R; //import com.xiaopeng.common.redis.service.RedisService; //import com.xiaopeng.order.service.IXpOrderService; //import com.xiaopeng.order.utils.holiday.HolidayUtil; //import lombok.extern.slf4j.Slf4j; //import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.stereotype.Component; // //import java.math.BigDecimal; //import java.math.RoundingMode; //import java.util.Calendar; //import java.util.Date; //import java.util.concurrent.TimeUnit; // ///** // * 计算价格的工具类 // */ //@Slf4j //@Component //public class XpPricingUtil { // // @Autowired // private HolidayUtil holidayUtil; // // @Autowired // private RedisService redisService; // @Autowired // private IXpOrderService orderService; // // /** // * 获取起步里程 // * // * @param startingFareJsonStr // * @return // */ // public static Integer getStartMileage(String startingFareJsonStr) { // Date date = new Date(); // JSONArray startingFareJson = JSONObject.parseArray(startingFareJsonStr); // for (Object o : startingFareJson) { // JSONObject startingFare = (JSONObject) o; // Calendar calendarStart = Calendar.getInstance(); // calendarStart.setTime(date); // calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num1").split(":")[0])); // calendarStart.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num1").split(":")[1])); // // Calendar calendarEnd = Calendar.getInstance(); // calendarEnd.setTime(date); // calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num2").split(":")[0])); // calendarEnd.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num2").split(":")[1])); // // 找到符合条件的直接跳出循环 // if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { // Integer mileage = startingFare.getInteger("num4"); // return mileage; // } // } // return null; // } // // // /** // * 计算基础价格 // * @param uid 用户id // * @param rule 基础规则 // * @param distance 里程 // * @param duration 时间 // * @param isDynamicPriceStatus 是否开启动态调价 // * // * @param openCityId 开通城市id // * @return // * @throws Exception // */ // public XpPricingCardVo calculationPrice(String uid, JSONObject rule, // JSONArray startingFareJson, // String dynamicPricingJson, // Integer isDynamicPriceStatus, // double distance, // long duration, // Long openCityId) { // // 默认费率1 // double priceRate = 1; // if (isDynamicPriceStatus == 1) { // // 先判断是否已经调价过了 // Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid); // if (userDynamicPriceObj != null) { // // 是否调价过了 // priceRate = Double.parseDouble(userDynamicPriceObj.toString()); // } else { // // 没有调过 // //是否触发动态调价 redis获取 // Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + openCityId); // if (dynamicPriceObj != null) { // JSONObject jsonObject = JSONObject.parseObject(dynamicPricingJson); // // 触发动态调价 // // value=时间 // String timeStr = dynamicPriceObj.toString(); // // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率 // Integer num = orderService.getOrderNum(new GetOrderNumDto(timeStr, openCityId)); // // X单上升一次调价 // Integer orderNum = getOrderNum(jsonObject, 4); // // 需要调价的次数 // int count = num / orderNum; // if (count > 0) { // // 计算每次上升的费率 // Integer upRate = getOrderNum(jsonObject, 5); // BigDecimal divide = new BigDecimal(upRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); // for (int i = count; i > 0; i--) { // // 当前费率+(费率*上升百分比) // priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); // } // // 冷却时间 // Integer time = getOrderNum(jsonObject, 6); // // 触发调价了 // redisService.setCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid, priceRate, time.longValue(), TimeUnit.MINUTES); // } // // } // } // // } // // // XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); // double amount = 0; // //等待费 // Date date = new Date(); // // 计算出是在那个时间段内 // for (Object o : startingFareJson) { // JSONObject startingFare = (JSONObject) o; // Calendar calendarStart = Calendar.getInstance(); // calendarStart.setTime(date); // calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num1").split(":")[0])); // calendarStart.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num1").split(":")[1])); // // Calendar calendarEnd = Calendar.getInstance(); // calendarEnd.setTime(date); // calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num2").split(":")[0])); // calendarEnd.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num2").split(":")[1])); // // 找到符合条件的直接跳出循环 // if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { // rule.put("num1", startingFare.get("num3")); // rule.put("num2", startingFare.get("num4")); // rule.put("num3", startingFare.get("num5")); // rule.put("num4", startingFare.get("num6")); // rule.put("num5", startingFare.get("num7")); // // rule.put("startTime", startingFare.getString("num1")); // rule.put("endTime", startingFare.getString("num2")); // break; // } // } // // // double realDistance = distance / 1000;//实际公里 // double realTime = duration / 60;//实际时间 // double exceedDistance = (realDistance - rule.getDouble("num2")) < 0 ? 0 : realDistance - rule.getDouble("num2");//超出起步里程的公里 // double exceedTime = (realTime - rule.getDouble("num3")) < 0 ? 0 : realTime - rule.getDouble("num3");//超过起步分钟数的时间 // double longDistanceOne = 0;//远途1段 // double longDistanceTwo = 0;//远途2段 // double longDistanceThree = 0;//远途3段 // // // //夜间服务处理逻辑 // Calendar calendarNight = Calendar.getInstance(); // calendarNight.setTime(date); // calendarNight.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[0])); // calendarNight.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[1])); // // Calendar calendar = Calendar.getInstance(); // calendar.setTime(date); // calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[0])); // calendar.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[1])); // // // 先判断今日是否节假日 // boolean holiday = holidayUtil.isHoliday(); // if (holiday) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num32") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num33") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num34") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num29") + (exceedDistance * rule.getDouble("num30")) + (exceedTime * rule.getDouble("num31")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num29")); // // 时间段 // xpPricingCardVo.setTime("节假日"); // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num30")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num31"))); // // // } else { // if (date.getTime() > calendarNight.getTimeInMillis() && date.getTime() < calendar.getTimeInMillis()) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num18") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num19") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num20") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num15") + (exceedDistance * rule.getDouble("num16")) + (exceedTime * rule.getDouble("num17")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num15")); // // 时间段 // xpPricingCardVo.setTime(rule.getString("num14")); // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num16")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num17"))); // // // } else { // // // 高峰处理 // Calendar calendarStart = Calendar.getInstance(); // calendarStart.setTime(date); // calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[0])); // calendarStart.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[1])); // // Calendar calendarEnd = Calendar.getInstance(); // calendarEnd.setTime(date); // calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[0])); // calendarEnd.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[1])); // // Calendar s2 = Calendar.getInstance(); // s2.setTime(date); // s2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[0])); // s2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[1])); // // Calendar e2 = Calendar.getInstance(); // e2.setTime(date); // e2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[0])); // e2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[1])); // //高峰时段处理逻辑 // if ((date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) || (date.getTime() > s2.getTimeInMillis() && date.getTime() < e2.getTimeInMillis())) { // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num26") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num27") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num28") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num23") + (exceedDistance * rule.getDouble("num24")) + (exceedTime * rule.getDouble("num25")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num23")); // // 时间段 // if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { // xpPricingCardVo.setTime(rule.getString("num21")); // } else { // xpPricingCardVo.setTime(rule.getString("num22")); // } // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num24")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num25"))); // // } else { // //其他时间段的计算 // if (realDistance > rule.getDouble("num6")) { // longDistanceOne = rule.getDouble("num8") * (realDistance - rule.getDouble("num6")); // } // if (realDistance > rule.getDouble("num9")) { // longDistanceTwo = rule.getDouble("num11") * (realDistance - rule.getDouble("num9")); // } // if (realDistance > rule.getDouble("num12")) { // longDistanceThree = rule.getDouble("num13") * (realDistance - rule.getDouble("num12")); // } // amount = rule.getDouble("num1") + (exceedDistance * rule.getDouble("num4")) + (exceedTime * rule.getDouble("num5")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; // // // // 起步价 // xpPricingCardVo.setStartPrice(rule.getDouble("num1")); // // 时间段 // xpPricingCardVo.setTime(rule.getString("startTime") + " - " + rule.getString("endTime")); // // xpPricingCardVo.setDistancePriceNormal(rule.getDouble("num2")); // // xpPricingCardVo.setDurationPriceNormal(rule.getDouble("num3")); // // // // 里程 // xpPricingCardVo.setDistance(realDistance); // // // 里程费 // double distancePrice = (exceedDistance * rule.getDouble("num4")) + longDistanceOne + longDistanceTwo + longDistanceThree; // xpPricingCardVo.setDistancePrice(distancePrice); // // // 时长 // xpPricingCardVo.setDuration(realTime); // // // 时长费 // xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num5"))); // // } // } // } // // // 订单总额 // Double startPrice = xpPricingCardVo.getStartPrice(); // // 先减去起步价重新计算 // amount = amount - startPrice; // // 动态计算费用 // startPrice = new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); // amount = amount + startPrice; // xpPricingCardVo.setTotalPrice(amount); // // // return xpPricingCardVo; // } // /** // * 行程结束后计算费用 // * @param rule 基础规则 // * @param distance 里程 // * @param duration 时间 // * @param wait 时间 // * @param waitMoney 等待费 // * @param openCityId 开通城市id // * @param isDynamicPriceStatus 是否开启动态调价 // * @return // * @throws Exception // */ //// public XpPricingCardVo calculationFinalPrice(String uid,JSONObject rule, JSONArray startingFareJson, double distance, long duration, long wait, Double waitMoney,Integer isDynamicPriceStatus,Long openCityId,String dynamicPricingJson) { //// //// //// // 默认费率1 //// double priceRate=1; //// if(isDynamicPriceStatus==1){ //// // 先判断是否已经调价过了 //// Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid); //// if(userDynamicPriceObj!=null){ //// // 是否调价过了 //// priceRate = Double.parseDouble(userDynamicPriceObj.toString()); //// }else { //// // 没有调过 //// //是否触发动态调价 redis获取 //// Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + openCityId); //// if(dynamicPriceObj!=null){ //// JSONObject jsonObject = JSONObject.parseObject(dynamicPricingJson); //// // 触发动态调价 //// // value=时间 //// String timeStr = dynamicPriceObj.toString(); //// // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率 //// R<Integer> r = xpOrderClient.getOrderNum(timeStr); //// if(r.getData()==200){ //// int num = r.getData(); //// // X单上升一次调价 //// Integer orderNum = getOrderNum(jsonObject, 4); //// // 需要调价的次数 //// int count = num / orderNum; //// if(count>0){ //// // 计算每次上升的费率 //// Integer upRate = getOrderNum(jsonObject, 5); //// BigDecimal divide = new BigDecimal(upRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); //// for (int i = count; i > 0; i--) { //// // 当前费率+(费率*上升百分比) //// priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); //// } //// //// // 冷却时间 //// Integer time = getOrderNum(jsonObject, 6); //// // 触发调价了 //// redisService.setCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid, priceRate,time.longValue(), TimeUnit.MINUTES); //// } //// } //// //// } //// } //// //// } //// //// //// //// XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); //// double amount = 0; //// //等待费 //// Date date = new Date(); //// // 计算出是在那个时间段内 //// for (Object o : startingFareJson) { //// JSONObject startingFare = (JSONObject) o; //// Calendar calendarStart = Calendar.getInstance(); //// calendarStart.setTime(date); //// calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num1").split(":")[0])); //// calendarStart.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num1").split(":")[1])); //// //// Calendar calendarEnd = Calendar.getInstance(); //// calendarEnd.setTime(date); //// calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(startingFare.getString("num2").split(":")[0])); //// calendarEnd.set(Calendar.MINUTE, Integer.valueOf(startingFare.getString("num2").split(":")[1])); //// // 找到符合条件的直接跳出循环 //// if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { //// rule.put("num1", startingFare.get("num3")); //// rule.put("num2", startingFare.get("num4")); //// rule.put("num3", startingFare.get("num5")); //// rule.put("num4", startingFare.get("num6")); //// rule.put("num5", startingFare.get("num7")); //// //// rule.put("startTime", startingFare.getString("num1")); //// rule.put("endTime", startingFare.getString("num2")); //// break; //// } //// } //// //// //// double realDistance = distance / 1000;//实际公里 //// double realTime = duration / 60;//实际时间 //// double exceedDistance = (realDistance - rule.getDouble("num2")) < 0 ? 0 : realDistance - rule.getDouble("num2");//超出起步里程的公里 //// double exceedTime = (realTime - rule.getDouble("num3")) < 0 ? 0 : realTime - rule.getDouble("num3");//超过起步分钟数的时间 //// double longDistanceOne = 0;//远途1段 //// double longDistanceTwo = 0;//远途2段 //// double longDistanceThree = 0;//远途3段 //// //// //// //夜间服务处理逻辑 //// Calendar calendarNight = Calendar.getInstance(); //// calendarNight.setTime(date); //// calendarNight.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[0])); //// calendarNight.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[0].split(":")[1])); //// //// Calendar calendar = Calendar.getInstance(); //// calendar.setTime(date); //// calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[0])); //// calendar.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num14").split(" - ")[1].split(":")[1])); //// //// // 先判断今日是否节假日 //// boolean holiday = holidayUtil.isHoliday(); //// if (holiday) { //// if (realDistance > rule.getDouble("num6")) { //// longDistanceOne = rule.getDouble("num32") * (realDistance - rule.getDouble("num6")); //// } //// if (realDistance > rule.getDouble("num9")) { //// longDistanceTwo = rule.getDouble("num33") * (realDistance - rule.getDouble("num9")); //// } //// if (realDistance > rule.getDouble("num12")) { //// longDistanceThree = rule.getDouble("num34") * (realDistance - rule.getDouble("num12")); //// } //// amount = rule.getDouble("num29") + (exceedDistance * rule.getDouble("num30")) + (exceedTime * rule.getDouble("num31")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; //// //// //// // 起步价 //// xpPricingCardVo.setStartPrice(rule.getDouble("num29")); //// // 时间段 //// xpPricingCardVo.setTime("节假日"); //// //// //// // 里程 //// xpPricingCardVo.setDistance(realDistance); //// //// // 里程费 //// double distancePrice = (exceedDistance * rule.getDouble("num30")) + longDistanceOne + longDistanceTwo + longDistanceThree; //// xpPricingCardVo.setDistancePrice(distancePrice); //// //// // 时长 //// xpPricingCardVo.setDuration(realTime); //// //// // 时长费 //// xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num31"))); //// //// //// } else { //// if (date.getTime() > calendarNight.getTimeInMillis() && date.getTime() < calendar.getTimeInMillis()) { //// if (realDistance > rule.getDouble("num6")) { //// longDistanceOne = rule.getDouble("num18") * (realDistance - rule.getDouble("num6")); //// } //// if (realDistance > rule.getDouble("num9")) { //// longDistanceTwo = rule.getDouble("num19") * (realDistance - rule.getDouble("num9")); //// } //// if (realDistance > rule.getDouble("num12")) { //// longDistanceThree = rule.getDouble("num20") * (realDistance - rule.getDouble("num12")); //// } //// amount = rule.getDouble("num15") + (exceedDistance * rule.getDouble("num16")) + (exceedTime * rule.getDouble("num17")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; //// //// //// // 起步价 //// xpPricingCardVo.setStartPrice(rule.getDouble("num15")); //// // 时间段 //// xpPricingCardVo.setTime(rule.getString("num14")); //// //// // 里程 //// xpPricingCardVo.setDistance(realDistance); //// //// // 里程费 //// double distancePrice = (exceedDistance * rule.getDouble("num16")) + longDistanceOne + longDistanceTwo + longDistanceThree; //// xpPricingCardVo.setDistancePrice(distancePrice); //// //// // 时长 //// xpPricingCardVo.setDuration(realTime); //// //// // 时长费 //// xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num17"))); //// //// //// } else { //// //// // 高峰处理 //// Calendar calendarStart = Calendar.getInstance(); //// calendarStart.setTime(date); //// calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[0])); //// calendarStart.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[0].split(":")[1])); //// //// Calendar calendarEnd = Calendar.getInstance(); //// calendarEnd.setTime(date); //// calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[0])); //// calendarEnd.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num21").split(" - ")[1].split(":")[1])); //// //// Calendar s2 = Calendar.getInstance(); //// s2.setTime(date); //// s2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[0])); //// s2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[0].split(":")[1])); //// //// Calendar e2 = Calendar.getInstance(); //// e2.setTime(date); //// e2.set(Calendar.HOUR_OF_DAY, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[0])); //// e2.set(Calendar.MINUTE, Integer.valueOf(rule.getString("num22").split(" - ")[1].split(":")[1])); //// //高峰时段处理逻辑 //// if ((date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) || (date.getTime() > s2.getTimeInMillis() && date.getTime() < e2.getTimeInMillis())) { //// if (realDistance > rule.getDouble("num6")) { //// longDistanceOne = rule.getDouble("num26") * (realDistance - rule.getDouble("num6")); //// } //// if (realDistance > rule.getDouble("num9")) { //// longDistanceTwo = rule.getDouble("num27") * (realDistance - rule.getDouble("num9")); //// } //// if (realDistance > rule.getDouble("num12")) { //// longDistanceThree = rule.getDouble("num28") * (realDistance - rule.getDouble("num12")); //// } //// amount = rule.getDouble("num23") + (exceedDistance * rule.getDouble("num24")) + (exceedTime * rule.getDouble("num25")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; //// //// //// // 起步价 //// xpPricingCardVo.setStartPrice(rule.getDouble("num23")); //// // 时间段 //// if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { //// xpPricingCardVo.setTime(rule.getString("num21")); //// } else { //// xpPricingCardVo.setTime(rule.getString("num22")); //// } //// //// //// // 里程 //// xpPricingCardVo.setDistance(realDistance); //// //// // 里程费 //// double distancePrice = (exceedDistance * rule.getDouble("num24")) + longDistanceOne + longDistanceTwo + longDistanceThree; //// xpPricingCardVo.setDistancePrice(distancePrice); //// //// // 时长 //// xpPricingCardVo.setDuration(realTime); //// //// // 时长费 //// xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num25"))); //// //// } else { //// //其他时间段的计算 //// if (realDistance > rule.getDouble("num6")) { //// longDistanceOne = rule.getDouble("num8") * (realDistance - rule.getDouble("num6")); //// } //// if (realDistance > rule.getDouble("num9")) { //// longDistanceTwo = rule.getDouble("num11") * (realDistance - rule.getDouble("num9")); //// } //// if (realDistance > rule.getDouble("num12")) { //// longDistanceThree = rule.getDouble("num13") * (realDistance - rule.getDouble("num12")); //// } //// amount = rule.getDouble("num1") + (exceedDistance * rule.getDouble("num4")) + (exceedTime * rule.getDouble("num5")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; //// //// //// // 起步价 //// xpPricingCardVo.setStartPrice(rule.getDouble("num1")); //// // 时间段 //// xpPricingCardVo.setTime(rule.getString("startTime") + " - " + rule.getString("endTime")); //// //// xpPricingCardVo.setDistancePriceNormal(rule.getDouble("num2")); //// //// xpPricingCardVo.setDurationPriceNormal(rule.getDouble("num3")); //// //// //// // 里程 //// xpPricingCardVo.setDistance(realDistance); //// //// // 里程费 //// double distancePrice = (exceedDistance * rule.getDouble("num4")) + longDistanceOne + longDistanceTwo + longDistanceThree; //// xpPricingCardVo.setDistancePrice(distancePrice); //// //// // 时长 //// xpPricingCardVo.setDuration(realTime); //// //// // 时长费 //// xpPricingCardVo.setDurationPrice((exceedTime * rule.getDouble("num5"))); //// //// } //// } //// } //// //// // 订单总额 //// Double startPrice = xpPricingCardVo.getStartPrice(); //// // 先减去起步价重新计算 //// amount = amount - startPrice; //// // 动态计算费用 //// startPrice= new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); //// amount = amount+startPrice; //// xpPricingCardVo.setTotalPrice(amount); //// //// //// return xpPricingCardVo; //// } // // // /** // * 获取配置 4每X单 5上升X% 6冷却 // * // * @param rule // * @param num // * @return // */ // private Integer getOrderNum(JSONObject rule, int num) { // Integer param = rule.getInteger("num" + num); // return param; // } //} xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/holiday/HolidayUtil.java
New file @@ -0,0 +1,80 @@ package com.xiaopeng.order.utils.holiday; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.utils.HttpUtils; import com.xiaopeng.common.redis.service.RedisService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.util.concurrent.TimeUnit; @Component public class HolidayUtil { @Autowired private RedisService redisService; public boolean isHoliday() { LocalDate now = LocalDate.now(); // 判断缓存里面是否有节假日算法 if (redisService.getCacheObject(CacheConstants.IS_HOLIDAY+now) != null && ("1").equals(redisService.getCacheObject(CacheConstants.IS_HOLIDAY+now).toString())) { return true; } String result = HttpUtil.get("https://publicapi.xiaoai.me/holiday/day?date=" +now); JSONObject jsonObject = JSONObject.parseObject(result); Object data = jsonObject.get("data"); JSONArray parse = JSONArray.parse(data.toString()); for (int i = 0; i < parse.size(); i++) { JSONObject jsonObject1 = parse.getJSONObject(i); if (jsonObject1.get("daytype").toString().equals("1")) { redisService.setCacheObject(CacheConstants.IS_HOLIDAY+now, "1", 1l, TimeUnit.DAYS); return true; } } redisService.setCacheObject(CacheConstants.IS_HOLIDAY+now, "0", 1l, TimeUnit.DAYS); return false; } /** * 2非工作日 0工作日 1节假日 3调休日 * @return */ public Integer isHolidayToday() { LocalDate now = LocalDate.now(); Object cacheObject = redisService.getCacheObject(CacheConstants.IS_DAY + now); // 判断缓存里面是否有节假日算法 if (cacheObject!=null) { return Integer.valueOf(cacheObject.toString()); } String result = HttpUtils.sendGet("https://publicapi.xiaoai.me/holiday/day?date=" +now); // String result = HttpUtils.sendGet("https://publicapi.xiaoai.me/holiday/day?date=2026-01-04"); JSONObject jsonObject = JSONObject.parseObject(result); Object data = jsonObject.get("data"); JSONArray parse = JSONArray.parse(data.toString()); for (int i = 0; i < parse.size(); i++) { JSONObject jsonObject1 = parse.getJSONObject(i); String daytype = jsonObject1.get("daytype").toString(); if (daytype.equals("0")) { redisService.setCacheObject(CacheConstants.IS_DAY + now, "0", 1l, TimeUnit.DAYS); return 0; } else if (daytype.equals("1")) { redisService.setCacheObject(CacheConstants.IS_DAY + now, "1", 1l, TimeUnit.DAYS); return 1; } else if (daytype.equals("2")) { redisService.setCacheObject(CacheConstants.IS_DAY + now, "0", 1l, TimeUnit.DAYS); return 0; } } return 0; } } xp-robotaxi-pushMessage-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java
New file @@ -0,0 +1,90 @@ package com.xiaopeng.pushMessage.controller; import com.alibaba.fastjson2.JSONObject; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.pushMessage.utils.MapMatchingUtil; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.*; @Api(tags = "订单推送轨迹接口") @RestController @RequestMapping("") public class PushOrderRouteController { @Autowired private RedisService redisService; @Autowired private XpPushMessageClient xpPushMessageClient; /** * 通过定位推送订单轨迹 * @return */ @PostMapping("/inner/v1/order/pushOrderRoute") public R<String> pushOrderRoute(@Validated @RequestBody PushOrderRouteDTO dto) { RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType()); if(Objects.nonNull(routeVo)){ // 计算实时点位到线段的最优截取 List<LonLatDto> lonLatDtos = MapMatchingUtil.clipBySegmentDistance(routeVo.getPolyline(), new LonLatDto(dto.getLongitude(), dto.getLatitude())); routeVo.setDistance(dto.getDistance()); routeVo.setDuration(dto.getDuration()); routeVo.setPolyline(lonLatDtos); // 存储最新路线偏离缓存,后续进行轨迹截取 redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); // 封装轨迹点位集合 Map<String, Object> polyline = new HashMap<>(); for (LonLatDto lonLatDto : lonLatDtos) { polyline.put("longitude",lonLatDto.getLongitude()); polyline.put("latitude",lonLatDto.getLatitude()); } // 封装路由详情 Map<String, Object> route = new HashMap<>(); route.put("distance",dto.getDistance()); route.put("duration",dto.getDuration()); route.put("polyline",JSONObject.toJSONString(polyline)); // 封装消息内容 Map<String, Object> content = new HashMap<>(); content.put("orderId",dto.getOrderId()); content.put("routeType",dto.getRouteType()); content.put("route",JSONObject.toJSONString(route)); // 封装轨迹信息 Map<String, Object> params = new HashMap<>(); params.put("type", PushMessageTypeEnum.ORDER_ROUTE.getDesc()); params.put("content", JSONObject.toJSONString(content)); params.put("timestamp", new Date().getTime()+""); // 进行消息推送 SendMessageDTO sendMessageDTO = new SendMessageDTO(); sendMessageDTO.setAppUserId(String.valueOf(dto.getAppUserId())); sendMessageDTO.setMessage(JSONObject.toJSONString(params)); xpPushMessageClient.sendRoute(sendMessageDTO); } return R.ok(); } } xp-robotaxi-pushMessage-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java
New file @@ -0,0 +1,123 @@ package com.xiaopeng.pushMessage.utils; import com.xiaopeng.api.dto.operation.LonLatDto; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.Collections; import java.util.List; @Slf4j public class MapMatchingUtil { /** * 轨迹裁剪(线段版本) * @param polyline * @param currentPoint * @return */ public static List<LonLatDto> clipBySegmentDistance(List<LonLatDto> polyline,LonLatDto currentPoint) { if (polyline == null || polyline.size() < 2) { return Collections.emptyList(); } double minDistance = Double.MAX_VALUE; int minSegmentIndex = 0; int increaseCount = 0; final int threshold = 3; final double tolerance = 1.0; for (int i = 0; i < polyline.size() - 1; i++) { double d = pointToSegmentDistance( currentPoint, polyline.get(i), polyline.get(i + 1) ); if (d < minDistance) { minDistance = d; minSegmentIndex = i; increaseCount = 0; } else if (d > minDistance + tolerance) { increaseCount++; } if (increaseCount >= threshold) { break; } } // 从最优线段的后一个点开始截取 return new ArrayList<>( polyline.subList(minSegmentIndex + 1, polyline.size()) ); } /** * 点到线段距离 * @param p * @param a * @param b * @return */ public static double pointToSegmentDistance( LonLatDto p, LonLatDto a, LonLatDto b) { double refLat = p.getLatitude(); double[] pXY = toXY(p.getLatitude(), p.getLongitude(), refLat); double[] aXY = toXY(a.getLatitude(), a.getLongitude(), refLat); double[] bXY = toXY(b.getLatitude(), b.getLongitude(), refLat); double x = pXY[0]; double y = pXY[1]; double x1 = aXY[0]; double y1 = aXY[1]; double x2 = bXY[0]; double y2 = bXY[1]; double dx = x2 - x1; double dy = y2 - y1; if (dx == 0 && dy == 0) { return Math.hypot(x - x1, y - y1); } double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); if (t < 0) { return Math.hypot(x - x1, y - y1); } else if (t > 1) { return Math.hypot(x - x2, y - y2); } double projX = x1 + t * dx; double projY = y1 + t * dy; return Math.hypot(x - projX, y - projY); } /** * 经纬度转平面坐标(局部近似) * @param lat * @param lon * @param refLat * @return */ private static double[] toXY(double lat, double lon, double refLat) { double R = 6378137; // 地球半径 double x = Math.toRadians(lon) * R * Math.cos(Math.toRadians(refLat)); double y = Math.toRadians(lat) * R; return new double[]{x, y}; } } xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -23,10 +23,12 @@ import com.xiaopeng.vehicleConvoy.model.exportExcel.XpVehicleExportExcel; import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; import com.xiaopeng.vehicleConvoy.model.query.*; import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; import com.xiaopeng.vehicleConvoy.service.IXpVehicleService; import io.swagger.annotations.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -371,6 +373,26 @@ } /** * 查询车辆位置信息 做筛选 * @param dto * @return */ @PostMapping("/inner/vehicle/queryVehiclePositionByVin") public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){ List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0).eq(XpVehicle::getStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin, dto.getVinList())); if(list.isEmpty()){ return R.ok(new ArrayList<>()); }else { List<String> vehiclePositionVos = new ArrayList<>(list.size()); for (XpVehicle xpVehicle : list) { vehiclePositionVos.add(xpVehicle.getVehicleVin()); } return R.ok(vehiclePositionVos); } } /** * 查询可改派的车辆列表 * * @return 车辆列表 @@ -441,7 +463,7 @@ * 业务流程-车门解锁/后备箱解锁 */ @ApiOperation(value = "打开车门操作", tags = {"小程序-业务流程"}) @PostMapping("/api/v1/order/vehicle/unlock") @PostMapping("/api/v1/mini-program/order/vehicle/unlock") public R<Integer> unlock(@RequestBody UnlockAppletDTO dto) { return R.ok(xpVehicleService.unlock(dto)); } @@ -450,7 +472,7 @@ * 业务流程-打开设置温度 */ @ApiOperation(value = "打开设置温度", tags = {"小程序-业务流程"}) @PostMapping("/api/v1/order/ac/set-temperature") @PostMapping("/api/v1/mini-program/order/ac/set-temperature") public R<Integer> setTemperature(@RequestBody SetTemperatureDTO dto) { return R.ok(xpVehicleService.setTemperature(dto)); } @@ -459,7 +481,7 @@ * 业务流程-通过订单id查询当前车辆温度 */ @ApiOperation(value = "通过订单id查询当前车辆温度", tags = {"小程序-业务流程"}) @GetMapping("/api/v1/order/queryTemperatureByOrderId") @GetMapping("/api/v1/mini-program/order/queryTemperatureByOrderId") public R<VehicleTemperatureDto> queryTemperatureByOrderId(@RequestParam Long orderId, HttpServletRequest request) { String uid = request.getHeader("XP-Uid"); VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId,uid);