puzhibing
2026-05-18 d8440cc93f48e5a4b932d8daf740023e16d65008
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java
@@ -15,6 +15,7 @@
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.map.RouteStaleCheckDto;
import com.xiaopeng.api.dto.map.SelectNavigationRouteDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.enums.RouteStrategyKind;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.account.UserRoutePlanRuleClient;
@@ -375,11 +376,9 @@
                Double money = userCouponVo.getMoney();
                money = new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).doubleValue();
                xpPricingCardVo.setCoupon(String.valueOf(money));
                if (xpPricingCardVo.getTotalPrice() > money) {
                    xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
                }
//                if (xpPricingCardVo.getTotalPrice() > money) {
//                    xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
//                }
            }
            // 8. 构建响应对象
@@ -390,7 +389,7 @@
            xpPricingCardVo.setStartPriceStr(new BigDecimal(xpPricingCardVo.getStartPrice()).setScale(2, RoundingMode.HALF_UP).toString());
            xpPricingCardVo.setDistancePriceStr(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2, RoundingMode.HALF_UP).toString());
            xpPricingCardVo.setDurationPriceStr(new BigDecimal(xpPricingCardVo.getDurationPrice()).setScale(2, RoundingMode.HALF_UP).toString());
            xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
//            xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
            routeAndFareVo.setXpPricingCard(xpPricingCardVo);
@@ -410,16 +409,16 @@
                    fareVo.setDiscountAmount(userCouponVo.getMoney());
                    fareVo.setFinalFare(fareVo.getOriginalFare() - fareVo.getDiscountAmount());
                }
                if(fareVo.getFinalFare()>0){
                    fareVo.setSystemDiscount(fareVo.getFinalFare());
                    fareVo.setFinalFare(0.00);
                }
//                if(fareVo.getFinalFare()>0){
//                    fareVo.setSystemDiscount(fareVo.getFinalFare());
//                    fareVo.setFinalFare(0.00);
//                }
                fareVo.setCouponId(userCouponVo.getId());
            } else {
                fareVo.setDiscountAmount(0.00);
                fareVo.setFinalFare(fareVo.getOriginalFare());
                fareVo.setSystemDiscount(fareVo.getFinalFare());
                fareVo.setFinalFare(0.00);
//                fareVo.setSystemDiscount(fareVo.getFinalFare());
//                fareVo.setFinalFare(0.00);
            }
            // 10. 检查等待时间
@@ -438,7 +437,7 @@
            // 12. 设置费用信息
            fareVo.setFinalFareStr(new BigDecimal(fareVo.getFinalFare()).setScale(2, RoundingMode.HALF_UP).toString());
            fareVo.setOriginalFare(new BigDecimal(fareVo.getOriginalFare()).setScale(2,RoundingMode.HALF_UP).doubleValue());
            fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2,RoundingMode.HALF_UP).doubleValue());
//            fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2,RoundingMode.HALF_UP).doubleValue());
            routeAndFareVo.setFareEstimate(fareVo);
            routeAndFareVo.getXpPricingCard().setFinalFareStr(fareVo.getFinalFareStr());
@@ -565,19 +564,19 @@
    @Override
    public String saveOrder(XpOrderDto dto, String uid) {
        //校验白名单用户
//        UcUserInfo userInfo = userResourcesClient.getBaseUserByUid(uid);
//        XpWhitelist xpWhitelist = xpWhitelistMapper.selectOne(new QueryWrapper<XpWhitelist>().eq("account", userInfo.getMobile())
//                .eq("status", 1).last(" and (DATE(expire_time) < DATE(NOW()) or expire_time is null)"));
//        if(null == xpWhitelist){
//            throw new ServiceException("未授权用户,不能使用该功能", I18nKeyConstant.NO_PERMISSION);
//        }
        List<XpWhitelist> xpWhitelists = xpWhitelistMapper.selectList(new QueryWrapper<XpWhitelist>().eq("app_user_id", uid)
                .eq("status", 1).eq("is_deleted", 0).last(" and (expire_time >= DATE(NOW()) or expire_time is null)"));
        if(xpWhitelists.isEmpty()){
            throw new ServiceException("未授权用户,不能使用该功能", I18nKeyConstant.NO_PERMISSION);
        }
        XpWhitelist xpWhitelist = xpWhitelists.get(0);
        //判断最大下单数
//        if(null != xpWhitelist.getMaxOrderNum() && xpWhitelist.getMaxOrderNum()>0){
//            Long count = xpOrderClient.getUserOrderNum(Long.valueOf(uid)).getData();
//            if(xpWhitelist.getMaxOrderNum() <= count){
//                throw new ServiceException("已达到最大下单数量,不能使用该功能", I18nKeyConstant.MAX_ORDER_NUM);
//            }
//        }
        if(null != xpWhitelist.getMaxOrderNum() && xpWhitelist.getMaxOrderNum()>0){
            Long count = xpOrderClient.getUserOrderNum(Long.valueOf(uid)).getData();
            if(xpWhitelist.getMaxOrderNum() <= count){
                throw new ServiceException("已达到最大下单数量,不能使用该功能", I18nKeyConstant.MAX_ORDER_NUM);
            }
        }
        // 是否在运营区域时间内
        XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(dto.getXpElectronicFenceAreaId());
@@ -765,11 +764,12 @@
        }
        //获取定向服务配置
        R<List<XpTargetedServiceVehicleVo>> targetedServiceUserR = xpTargetedServiceClient.findListByUserIdAndCityCode(xpOrder.getAppUserId(), xpOrder.getCityCode());
        if(targetedServiceUserR.getCode() == R.SUCCESS && CollUtil.isNotEmpty(targetedServiceUserR.getData()) ){
            XpTargetedServiceVehicleVo xpTargetedServiceVehicleVo = targetedServiceUserR.getData().get(0);
            return addSpOrderPush(xpOrder, xpPoint, xpRoutePlan, maxPushDistance, xpTargetedServiceVehicleVo, orderId, currentTimeSlot, distance, duration, uid);
        R<Integer> targetedServiceWeight = xpTargetedServiceClient.getTargetedServiceWeight(xpOrder.getAppUserId(), xpOrder.getCityCode());
        if(targetedServiceWeight.getCode() == R.SUCCESS && null != targetedServiceWeight.getData()){
            log.info("添加定向服务订单:{}", xpOrder.getOrderNumber());
            return addSpOrderPush(xpOrder, xpPoint, xpRoutePlan, maxPushDistance, targetedServiceWeight.getData(), orderId, currentTimeSlot, distance, duration, uid);
        }else{
            log.info("添加普通订单:{}", xpOrder.getOrderNumber());
            return addOrderPush(xpOrder, xpPoint, xpRoutePlan, maxPushDistance, isPriorityDispatch, orderId, currentTimeSlot, distance, duration, uid);
        }
    }
@@ -858,7 +858,7 @@
     * @param xpPoint
     * @param xpRoutePlan
     * @param maxPushDistance
     * @param xpTargetedServiceVehicleVo
     * @param weight
     * @param orderId
     * @param currentTimeSlot
     * @param distance
@@ -867,10 +867,10 @@
     * @return
     */
    private String addSpOrderPush(XpOrder xpOrder, XpPoint xpPoint, XpRoutePlan xpRoutePlan, double maxPushDistance,
                                  XpTargetedServiceVehicleVo xpTargetedServiceVehicleVo, Long orderId, String currentTimeSlot, Integer distance, Integer duration, String uid){
                                  Integer weight, Long orderId, String currentTimeSlot, Integer distance, Integer duration, String uid){
        // 找出现在所有的队列 通过计算距离 算出目前应该放在那个队列  如果没有符合的新增一个队列  符合后看是否白名单账号 是则直接放在队列前端
        Set<String> quoteMatchName = redisService.getQuoteMatchName(CacheConstants.SP_QUEUE_POINT_ID);
        log.info("当前队列:{}", quoteMatchName);
        log.info("当前队列(定向服务):{}", quoteMatchName);
        for (String s : quoteMatchName) {
//            QUEUE_POINT_ID-1-30.233,120.233
@@ -905,7 +905,7 @@
                redisQueuePointIdVo.setDistance(distance.toString());
                redisQueuePointIdVo.setDuration(duration.toString());
                redisQueuePointIdVo.setPlanRuleForQueue(xpRoutePlan.getRoutePlanRule().toString());
                redisQueuePointIdVo.setTargetedVal(xpTargetedServiceVehicleVo.getWeight());
                redisQueuePointIdVo.setTargetedVal(weight);
                ll.add(redisQueuePointIdVo);
                //排序
                ll.sort((o1, o2) -> o2.getTargetedVal() - o1.getTargetedVal());
@@ -935,9 +935,9 @@
        String key = CacheConstants.SP_QUEUE_POINT_ID + "-" + xpPoint.getId() + "-" + xpPoint.getPointLon() + "," + xpPoint.getPointLat();
        if(xpRoutePlan==null){
            redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + null + "_" + xpTargetedServiceVehicleVo.getWeight()));
            redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + null + "_" + weight));
        }else {
            redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + xpRoutePlan.getRoutePlanRule() + "_" + xpTargetedServiceVehicleVo.getWeight()));
            redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + xpRoutePlan.getRoutePlanRule() + "_" + weight));
        }
        log.info("订单推单:{}   {}", key, redisService.getCacheList(key));
        xpOrder.setQueueName(key);
@@ -1064,9 +1064,9 @@
            Double money = userCouponVo.getMoney();
            money = new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).doubleValue();
            xpPricingCardVo.setCoupon(String.valueOf(money));
            if (xpPricingCardVo.getTotalPrice() > money) {
                xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
            }
//            if (xpPricingCardVo.getTotalPrice() > money) {
//                xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
//            }
        }
        RouteAndFareVo routeAndFareVo = new RouteAndFareVo();
        routeAndFareVo.setRoute(routeVo);
@@ -1074,7 +1074,7 @@
        xpPricingCardVo.setStartPriceStr(new BigDecimal(xpPricingCardVo.getStartPrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setDistancePriceStr(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setDurationPriceStr(new BigDecimal(xpPricingCardVo.getDurationPrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
//        xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
        routeAndFareVo.setXpPricingCard(xpPricingCardVo);
        FareVo fareVo = new FareVo();
        fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
@@ -1089,22 +1089,17 @@
                fareVo.setDiscountAmount(userCouponVo.getMoney());
                fareVo.setFinalFare(fareVo.getOriginalFare() - fareVo.getDiscountAmount());
            }
            if (fareVo.getFinalFare() > 0) {
                fareVo.setSystemDiscount(fareVo.getFinalFare());
                fareVo.setFinalFare(0.00);
            }
            fareVo.setCouponId(userCouponVo.getId());
        } else {
            fareVo.setDiscountAmount(0.00);
            fareVo.setFinalFare(fareVo.getOriginalFare());
            fareVo.setSystemDiscount(fareVo.getFinalFare());
            fareVo.setFinalFare(0.00);
//            fareVo.setSystemDiscount(fareVo.getFinalFare());
        }
        Integer waitTime = getWaitTime(routeAndFareDto.getOrigin().getLongitude(), routeAndFareDto.getOrigin().getLatitude());
        fareVo.setWaitingTime(waitTime);
        fareVo.setFinalFareStr(new BigDecimal(fareVo.getFinalFare()).setScale(2, RoundingMode.HALF_UP).toString());
        fareVo.setOriginalFare(new BigDecimal(fareVo.getOriginalFare()).setScale(2, RoundingMode.HALF_UP).doubleValue());
        fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
//        fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
        routeAndFareVo.setFareEstimate(fareVo);
        routeAndFareVo.getXpPricingCard().setFinalFareStr(fareVo.getFinalFareStr());
//        routeAndFareVo.setTrafficLights();//交通信号灯 todo 20260508 红绿灯功能还没有
@@ -1139,22 +1134,36 @@
        StrategyPlanningConfig planningConfig = this.buildStrategyKindsForPlanning(userId, routeAndFareDto.getOpenCityId());
        List<RouteStrategyKind> kinds = planningConfig.getKinds();
        Map<String, RouteVo> routeById = new LinkedHashMap<>();
        Map<String, Set<RouteStrategyKind>> strategiesById = new LinkedHashMap<>();
        for (RouteStrategyKind kind : kinds) {
        Map<String, RouteStrategyKind> strategiesById = new HashMap<>();
        List<RouteVo> routePoints = new ArrayList<>();
        List<XpRoutePlan> xpRoutePlans = xpRoutePlanMapper.selectList(new LambdaQueryWrapper<XpRoutePlan>().eq(XpRoutePlan::getOpenCityId, routeAndFareDto.getOpenCityId())
                .eq(XpRoutePlan::getAuditStatus, 2));
        log.info("导航策略配置 {} {}", routeAndFareDto.getOpenCityId(), JSON.toJSONString(xpRoutePlans));
        for (XpRoutePlan xpRoutePlan : xpRoutePlans) {
            RouteAndFareDto copy = new RouteAndFareDto();
            copy.setOrigin(routeAndFareDto.getOrigin());
            copy.setDestination(routeAndFareDto.getDestination());
            copy.setRoutePlanRule(kind.getAmapStrategy());
            R<RouteVo> r = xpMapClient.getDistanceAndDuration(copy);
            if (r.getCode() != 200 || r.getData() == null || r.getData().getRouteID() == null) {
            copy.setRoutePlanRule(xpRoutePlan.getRoutePlanRule());
            R<List<RouteVo>> r = xpMapClient.getDistanceAndDurationList(copy);
            if (r.getCode() != 200 || r.getData() == null || r.getData().isEmpty()) {
                continue;
            }
            String fid = r.getData().getRouteID();
            routeById.putIfAbsent(fid, r.getData());
            strategiesById.computeIfAbsent(fid, k -> new LinkedHashSet<>()).add(kind);
            bb: for (RouteVo datum : r.getData()) {
                for (RouteVo routePoint : routePoints) {
                    if(CollUtil.isEqualList(routePoint.getPolyline(), datum.getPolyline())){
                        continue bb;
                    }
                }
                routePoints.add(datum);
                RouteStrategyKind routeStrategyKind = kinds.stream().filter(kind -> kind.getAmapStrategy() == xpRoutePlan.getRoutePlanRule()).findFirst().get();
                strategiesById.put(datum.getRouteID(), routeStrategyKind);
                break;
            }
        }
        if (routeById.isEmpty()) {
        if (routePoints.isEmpty()) {
            throw new ServiceException("获取导肮信息失败", I18nKeyConstant.PATH_NOT_FOUND);
        }
@@ -1166,25 +1175,19 @@
        }
        List<RouteOptionVo> options = new ArrayList<>();
        for (Map.Entry<String, RouteVo> e : routeById.entrySet()) {
            String fid = e.getKey();
            RouteVo rv = e.getValue();
            Set<RouteStrategyKind> kindsOnRoute = strategiesById.get(fid);
            RouteStrategyKind primary = RouteStrategyKind.primaryOf(kindsOnRoute);
        for (RouteVo routePoint : routePoints) {
            RouteAndFareDto pricingDto = new RouteAndFareDto();
            pricingDto.setOrigin(routeAndFareDto.getOrigin());
            pricingDto.setDestination(routeAndFareDto.getDestination());
            pricingDto.setOpenCityId(routeAndFareDto.getOpenCityId());
            pricingDto.setUserCouponId(routeAndFareDto.getUserCouponId());
            pricingDto.setVehicleId(routeAndFareDto.getVehicleId());
            pricingDto.setRoutePlanRule(primary.getAmapStrategy());
            RouteAndFareVo part = pricingForRoute(pricingDto, rv, xpPricing, userId);
            //计算导航对应的费用
            RouteAndFareVo part = pricingForRoute(pricingDto, routePoint, xpPricing, userId);
            RouteOptionVo opt = new RouteOptionVo();
            opt.setPathFingerprint(fid);
            List<String> labels = RouteStrategyKind.orderedOf(kindsOnRoute).stream()
                    .map(kind -> resolveStrategyDisplayName(kind, planningConfig.getDisplayNames()))
                    .collect(Collectors.toList());
            opt.setStrategyLabels(labels);
            opt.setPathFingerprint(routePoint.getRouteID());
            RouteStrategyKind primary = strategiesById.get(routePoint.getRouteID());
            opt.setStrategyLabels(Arrays.asList(primary.getDisplayName()));
            opt.setPrimaryStrategyLabel(resolveStrategyDisplayName(primary, planningConfig.getDisplayNames()));
            opt.setPrimaryRoutePlanRule(primary.getAmapStrategy());
            opt.setPrimaryRoutePlanName(primary.getDisplayName());
@@ -1198,17 +1201,8 @@
            options.add(opt);
        }
        // 根据 pathFingerprint 去重,保留第一次出现的路线
//        options = new ArrayList<>(options.stream()
//                .collect(Collectors.toMap(
//                        RouteOptionVo::getPathFingerprint,
//                        option -> option,
//                        (existing, replacement) -> existing,
//                        LinkedHashMap::new
//                )).values());
        RouteStrategyKind userPref = resolveUserPreferredKind(userId).orElse(RouteStrategyKind.SMART);
        options.sort((a, b) -> compareRouteOptionByUserPreference(a, b, userPref, strategiesById));
        options.sort((a, b) -> compareRouteOptionByUserPreference(a, b, userPref));
        String snapshotId = UUID.randomUUID().toString().replace("-", "");
        long now = System.currentTimeMillis();
@@ -1236,7 +1230,8 @@
        vo.setStaleCheckSeconds(navigationStaleSeconds);
        vo.setPriceWaveThresholdPercent(navigationPriceWavePercent);
        vo.setOperateFree(operateFree);
        //产品喊写死
        vo.setMaxPeopleNumber(5);
        RouteOptionVo first = options.get(0);
        redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + userId, JSON.toJSONString(first.getRoute()), 24L, TimeUnit.HOURS);
@@ -1451,23 +1446,12 @@
        }
    }
    private int compareRouteOptionByUserPreference(RouteOptionVo a, RouteOptionVo b, RouteStrategyKind pref,
                                                   Map<String, Set<RouteStrategyKind>> strategiesById) {
        Set<RouteStrategyKind> sa = strategiesById.getOrDefault(a.getPathFingerprint(), Collections.emptySet());
        Set<RouteStrategyKind> sb = strategiesById.getOrDefault(b.getPathFingerprint(), Collections.emptySet());
        boolean aHas = sa.contains(pref);
        boolean bHas = sb.contains(pref);
        if (aHas != bHas) {
            return bHas ? 1 : -1;
    private int compareRouteOptionByUserPreference(RouteOptionVo a, RouteOptionVo b, RouteStrategyKind pref) {
        Integer primaryRoutePlanRule = a.getPrimaryRoutePlanRule();
        if(primaryRoutePlanRule == pref.getAmapStrategy()){
            return 1;
        }
        boolean aPrimary = a.getPrimaryRoutePlanRule() != null && a.getPrimaryRoutePlanRule() == pref.getAmapStrategy();
        boolean bPrimary = b.getPrimaryRoutePlanRule() != null && b.getPrimaryRoutePlanRule() == pref.getAmapStrategy();
        if (aPrimary != bPrimary) {
            return bPrimary ? 1 : -1;
        }
        int da = a.getRoute() != null && a.getRoute().getDuration() != null ? a.getRoute().getDuration() : Integer.MAX_VALUE;
        int db = b.getRoute() != null && b.getRoute().getDuration() != null ? b.getRoute().getDuration() : Integer.MAX_VALUE;
        return Integer.compare(da, db);
        return -1;
    }
    @Override
@@ -1509,9 +1493,10 @@
            int totalCount = queueItems.size();
            for (int i = 0; i < queueItems.size(); i++) {
                currentPosition++;
                String item = queueItems.get(i);
                if (item.startsWith(orderId + "_")) {
                    currentPosition = i + 1; // 位置从1开始
                String[] split = item.split("_");
                if (split[0].equals(orderId + "")) {
                    break;
                }
            }