From c96fbe6b0aeb413a17c429133ee6d81d138144b9 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期二, 09 六月 2026 10:58:52 +0800
Subject: [PATCH] Merge branch '1.0' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi into 1.0

---
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java |  356 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 287 insertions(+), 69 deletions(-)

diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
index a3964c5..4a37637 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -1,9 +1,13 @@
 package com.xiaopeng.operation.service.impl;
 
 
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
+import cn.hutool.core.lang.Snowflake;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.xiaopeng.api.dto.account.GetUserCouponDto;
@@ -11,9 +15,10 @@
 import com.xiaopeng.api.dto.operation.LonLatDto;
 import com.xiaopeng.api.feignClient.account.XpAppUserClient;
 import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
+import com.xiaopeng.api.feignClient.maintenance.XpVehicleModelClient;
 import com.xiaopeng.api.feignClient.map.XpMapClient;
 import com.xiaopeng.api.feignClient.order.XpOrderClient;
-import com.xiaopeng.api.model.account.XpAppUser;
+import com.xiaopeng.api.model.maintenance.XpVehicleModel;
 import com.xiaopeng.api.model.operation.*;
 import com.xiaopeng.api.model.order.XpOrder;
 import com.xiaopeng.api.vo.account.UserCouponVo;
@@ -25,22 +30,26 @@
 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.StringUtils;
 import com.xiaopeng.common.core.utils.uuid.UUID;
 import com.xiaopeng.common.core.web.page.PageInfo;
 import com.xiaopeng.common.redis.service.RedisService;
 import com.xiaopeng.operation.constant.I18nKeyConstant;
-import com.xiaopeng.operation.dto.PricingAddDTO;
-import com.xiaopeng.operation.dto.PricingSetPriceDTO;
-import com.xiaopeng.operation.dto.PricingSetRuleDTO;
-import com.xiaopeng.operation.dto.XpOrderDto;
+import com.xiaopeng.operation.dto.*;
+import com.xiaopeng.operation.job.base.QuartzManager;
+import com.xiaopeng.operation.job.base.TimeJobType;
+import com.xiaopeng.operation.job.jobs.DynamicPricingCheckJob;
 import com.xiaopeng.operation.mapper.*;
 import com.xiaopeng.operation.query.PricingPageListQuery;
 import com.xiaopeng.operation.service.IXpGeoQueryEntityService;
+import com.xiaopeng.operation.service.XpPointService;
 import com.xiaopeng.operation.service.XpPricingService;
 import com.xiaopeng.operation.utils.XpPricingUtil;
 import com.xiaopeng.operation.utils.holiday.HolidayUtil;
 import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
+import com.xiaopeng.operation.vo.PricingInfoVo;
 import com.xiaopeng.operation.vo.PricingPageListVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
 import org.springframework.stereotype.Service;
@@ -48,6 +57,7 @@
 import javax.annotation.PreDestroy;
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -61,6 +71,7 @@
  * @author liu
  * @since 2026-02-03
  */
+@Slf4j
 @Service
 public class XpPricingServiceImpl extends ServiceImpl<XpPricingMapper, XpPricing> implements XpPricingService {
 
@@ -97,8 +108,7 @@
 
 
     @Resource
-    private XpPointMapper xpPointMapper;
-
+    private XpVehicleModelClient xpVehicleModelClient;
     @Resource
     private XpWhitelistMapper xpWhitelistMapper;
 
@@ -113,6 +123,12 @@
 
     @Autowired
     private XpElectronicFenceMapper xpElectronicFenceMapper;
+
+    @Autowired
+    private XpPointService xpPointService;
+
+    @Resource(name = "hutoolSnowflake")
+    private Snowflake snowflake;
 
 
     // 自定义线程池用于并行执行任务
@@ -171,6 +187,7 @@
 
 
     @Override
+    @Deprecated
     public RouteAndFareVo getRouteAndFare(RouteAndFareDto routeAndFareDto, String userId) {
 
 
@@ -198,18 +215,37 @@
         }
 
         XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, routeAndFareDto.getOpenCityId()));
-//        if (xpPricing == null) {
-//            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
-//        }
+        if (xpPricing == null) {
+            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
+        }
+
+
+
+//        // 算距离
+        R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
+        if(distanceAndDuration.getCode()!=200){
+            throw new ServiceException("未找到路径", I18nKeyConstant.PATH_NOT_FOUND);
+        }
+
+
+        RouteVo routeVo = distanceAndDuration.getData();
 
         // 2. 计算价格(需要在并行任务前完成,因为优惠券查询需要价格)
-//        XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationPrice(
-//                JSON.parseObject(xpPricing.getBasicPricingJson()),
-//                JSON.parseArray(xpPricing.getStartingFareJson()),
-//                1, 1, 0, 0.0
-//        );
-        XpPricingCardVo xpPricingCardVo = new XpPricingCardVo();
 
+        XpPricingCardVo xpPricingCardVo;
+        if (xpPricing.getPricingType() == 1) {
+            xpPricingCardVo = xpPricingUtil.calculationPrice(userId,
+                    JSON.parseObject(xpPricing.getBasicPricingJson()),
+                    JSON.parseArray(xpPricing.getStartingFareJson()),
+                    routeVo.getDistance(), routeVo.getDuration(), 0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
+            );
+        } else {
+            xpPricingCardVo = xpPricingUtil.calculationFixedPrice(userId,
+                    JSON.parseObject(xpPricing.getBasicPricingJson()),
+                    JSON.parseArray(xpPricing.getStartingFareJson()),
+                    routeVo.getDistance(), routeVo.getDuration(),0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
+            );
+        }
 
 
         // 3. 并行执行远程服务调用 判断是否同一经营区域
@@ -218,19 +254,15 @@
                 executorService
         );
 
-//        // 算距离
-//        CompletableFuture<R<RouteVo>> routeFuture = CompletableFuture.supplyAsync(
-//                () -> xpMapClient.getDistanceAndDuration(routeAndFareDto),
-//                executorService
-//        );
 
         // 优惠券
+        XpPricingCardVo finalXpPricingCardVo = xpPricingCardVo;
         CompletableFuture<R<UserCouponVo>> couponFuture = CompletableFuture.supplyAsync(
                 () -> {
                     // 优惠券
                     return xpAppUserCouponClient.getUserCoupon(
-//                                new GetUserCouponDto(Long.valueOf(userId), xpPricingCardVo.getTotalPrice(),routeAndFareDto.getOpenCityId())
-                            new GetUserCouponDto(Long.valueOf(userId), 1d, routeAndFareDto.getOpenCityId())
+                                new GetUserCouponDto(Long.valueOf(userId), finalXpPricingCardVo.getTotalPrice(),routeAndFareDto.getOpenCityId(),null)
+//                            new GetUserCouponDto(Long.valueOf(userId), 1d, routeAndFareDto.getOpenCityId())
                     );
                 },
                 executorService
@@ -238,7 +270,6 @@
 
         // 4. 等待所有并行任务完成并获取结果
         R<Boolean> diagnosisResult = diagnosisAreaFuture.join();
-//        R<RouteVo> routeResult = routeFuture.join();
         R<UserCouponVo> couponResult = couponFuture.join();
 
         // 5. 处理诊断结果
@@ -249,7 +280,7 @@
             throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
         }
 
-        // 6. 处理路线结果
+//        // 6. 处理路线结果
 //        if (routeResult.getCode() != 200) {
 //            throw new RuntimeException(routeResult.getMsg());
 //        }
@@ -263,9 +294,9 @@
         } else {
             minOrderDistance = systemSettingMapper.selectOne(null).getMinOrderDistance();
         }
-//        if (routeVo.getDistance() < Integer.valueOf(minOrderDistance)) {
-//            throw new ServiceException("当前上下车点距离过近,建议步行前往", I18nKeyConstant.TO_WORK);
-//        }
+        if (routeVo.getDistance() < Integer.valueOf(minOrderDistance)) {
+            throw new ServiceException("当前上下车点距离过近,建议步行前往", I18nKeyConstant.TO_WORK);
+        }
 
         // 7. 处理优惠券结果
         if (couponResult.getCode() != R.SUCCESS) {
@@ -278,19 +309,46 @@
 
         // 8. 构建响应对象
         RouteAndFareVo routeAndFareVo = new RouteAndFareVo();
-//        routeAndFareVo.setRoute(routeVo);
+
+        // MOCK数据
+//        RouteVo routeVo = new RouteVo();
+//        routeVo.setDistance(3000);
+//        routeVo.setDuration(5);
+//        routeVo.setRouteID("1");
+//        List<LonLatDto> routePolyline = Arrays.asList(
+//                // 起点:天府新谷
+//                new LonLatDto(104.05363, 30.58937),
+//
+//                // 途经点1:府城大道与交子北二路交叉口附近
+//                new LonLatDto(104.05821, 30.58745),
+//
+//                // 途经点2:交子大道与成汉南路交叉口
+//                new LonLatDto(104.06418, 30.58492),
+//
+//                // 途经点3:交子大道与万象南路交叉口
+//                new LonLatDto(104.06975, 30.58321),
+//
+//                // 途经点4:交子大道与益州大道交叉口
+//                new LonLatDto(104.07366, 30.58198),
+//
+//                // 终点:金融城(地铁站附近)
+//                new LonLatDto(104.076544, 30.581039)
+//        );
+//        routeVo.setPolyline(routePolyline);
+        routeAndFareVo.setRoute(routeVo);
 
 
         routeAndFareVo.setXpPricingCard(xpPricingCardVo);
 
         FareVo fareVo = new FareVo();
-//        fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
-//        fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60);
+        fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
+        fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60);
 
         // 9. 设置费用信息
         fareVo.setOriginalFare(xpPricingCardVo.getTotalPrice());
         if (userCouponVo != null) {
             fareVo.setDiscountAmount(userCouponVo.getMoney());
+            fareVo.setCouponType(userCouponVo.getCouponType());
             fareVo.setFinalFare(fareVo.getOriginalFare() - fareVo.getDiscountAmount());
             fareVo.setCouponId(userCouponVo.getId());
         } else {
@@ -299,11 +357,11 @@
         }
 
         // 10. 检查等待时间
-        Integer waitTime = getWaitTime(routeAndFareDto.getOrigin().getLongitude(), routeAndFareDto.getOrigin().getLatitude());
-        if (waitTime > 3) {
-            throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME);
-        }
-        fareVo.setWaitingTime(waitTime);
+//        Integer waitTime = getWaitTime(routeAndFareDto.getOrigin().getLongitude(), routeAndFareDto.getOrigin().getLatitude());
+//        if (waitTime > 3) {
+//            throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME);
+//        }
+//        fareVo.setWaitingTime(waitTime);
 
 
         // 11. 生成订单ID并缓存
@@ -356,7 +414,7 @@
                     double waitMinutes = (average * count) / 60;
                     if (waitMinutes > 3) {
                         throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME);
-                    }else if(waitMinutes==0){
+                    } else if (waitMinutes == 0) {
                         return 1;
                     }
                     return (int) waitMinutes;
@@ -370,6 +428,7 @@
 
     @Override
     public Long saveOrder(XpOrderDto dto, String uid) {
+
         // 是否在运营区域时间内
         XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(dto.getXpElectronicFenceAreaId());
         XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceArea.getElectronicId());
@@ -384,24 +443,31 @@
         // 判断是否有进行的订单
         R<Long> r = xpOrderClient.hasUnPaodOrder(uid);
         if (r.getData() > 0) {
-            throw new RuntimeException("有正在进行的订单");
+            throw new ServiceException("有正在进行的订单", I18nKeyConstant.HAS_UNPAID_ORDER);
         }
 
         // 获取起点经纬度
-        XpPoint xpPoint = xpPointMapper.selectById(dto.getStartPointId());
+        XpPoint xpPoint = xpPointService.getById(dto.getStartPointId());
 
         // 终点
-        XpPoint endXpPoint = xpPointMapper.selectById(dto.getStartPointId());
+        XpPoint endXpPoint = xpPointService.getById(dto.getStartPointId());
 
-        // 判断当天取消的次数 后台配置 redis 查询
-        Object cancelOrder = redisService.getCacheObject("CANCEL_ORDER_" + uid);
+        // 判断点位是否在运营区域内
+        LocalTime now = LocalTime.now();
+        boolean inTime = xpPointService.getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
+        if (!inTime) {
+            throw new ServiceException("当前点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
+        }
+        inTime = xpPointService.getInTime(now, endXpPoint.getEffectivePeriod(), endXpPoint.getEffectiveTimePeriod());
+        if (!inTime) {
+            throw new ServiceException("当前点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
+        }
+
         // 静默处理
         boolean isSilent = false;
-        if (cancelOrder != null) {
-            Integer num = Integer.valueOf(cancelOrder.toString());
-            if (num >= cancelCount) {
-                isSilent =true;
-            }
+        Integer num = xpOrderClient.todayCancellationCount(Long.valueOf(uid)).getData();
+        if (num >= cancelCount) {
+            isSilent = true;
         }
 
 
@@ -415,14 +481,14 @@
 
         // 根据id获取手机号
 
-        Boolean isPriorityDispatch = false;
-        R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid));
-        if (xpAppUserR.getCode() == R.SUCCESS) {
-            Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1));
-            if (count > 0) {
-                isPriorityDispatch = true;
-            }
-        }
+        Boolean isPriorityDispatch = true;
+//        R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid));
+//        if (xpAppUserR.getCode() == R.SUCCESS) {
+//            Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1));
+//            if (count > 0) {
+//                isPriorityDispatch = true;
+//            }
+//        }
 
         // 生成订单数据
         XpOrder xpOrder = new XpOrder();
@@ -432,7 +498,7 @@
 //        xpOrder.setStartMileage(Double.valueOf(startMileage));
 
         xpOrder.setAppUserId(Long.valueOf(uid));
-        xpOrder.setOrderNumber("XP" + System.currentTimeMillis());
+        xpOrder.setOrderNumber(getOrderNumber());
         xpOrder.setPlacementLon(dto.getPlacementLon());
         xpOrder.setPlacementLat(dto.getPlacementLat());
         xpOrder.setPlacementAddress(dto.getPlacementAddress());
@@ -456,6 +522,8 @@
         xpOrder.setEndPointId(dto.getEndPointId());
         xpOrder.setStartPointName(xpPoint.getPointName());
         xpOrder.setEndPointName(endXpPoint.getPointName());
+        xpOrder.setXpuStartTaskId(snowflake.nextId() + "");
+        xpOrder.setXpuEndTaskId(snowflake.nextId() + "");
 
         // 当前时段
         String currentTimeSlot = DateUtils.getCurrentTimeSlot();
@@ -499,7 +567,7 @@
         Long orderId = addOrderR.getData();
 
         // 静默处理 不推单
-        if(isSilent){
+        if (isSilent) {
             return orderId;
         }
 
@@ -533,7 +601,7 @@
                 // 存储mongodb 数据
                 XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
                 xpGeoQueryEntity.setOrderId(orderId.toString());
-                xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat()));
+                xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(), xpPoint.getPointLat()));
                 // 计算2个时间的秒数
                 xpGeoQueryEntity.setTime(currentTimeSlot);
                 xpGeoQueryEntity.setStatus(0);
@@ -553,11 +621,11 @@
         // 存储mongodb 数据
         XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
         xpGeoQueryEntity.setOrderId(orderId.toString());
-        xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat()));
+        xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(), xpPoint.getPointLat()));
         // 计算2个时间的秒数
         xpGeoQueryEntity.setTime(currentTimeSlot);
         xpGeoQueryEntity.setStatus(0);
-
+        xpGeoQueryEntity.setTimestamp(System.currentTimeMillis());
         geoQueryEntityService.save(xpGeoQueryEntity);
 
         return orderId;
@@ -574,6 +642,11 @@
 
     }
 
+
+    private String getOrderNumber(){
+        int random = Double.valueOf(Math.random() * 1000).intValue();
+        return "XP" + random + System.currentTimeMillis();
+    }
 
     private Boolean isInOperationTime(String operationStrategy) {
         JSONArray jsonArray = JSONArray.parseArray(operationStrategy);
@@ -624,11 +697,28 @@
         Page<PricingPageListVO> page = this.baseMapper.pageList(pageInfo, query);
         pageInfo.setRecords(page.getRecords());
         pageInfo.setTotal(page.getTotal());
+        if(page.getRecords() != null){
+            Set<String> vehicleModelIds = page.getRecords().stream().map(PricingPageListVO::getVehicleModel).collect(Collectors.toSet());
+            R<List<XpVehicleModel>> listR = xpVehicleModelClient.listByIds(vehicleModelIds);
+            if(listR != null && listR.getData() != null){
+                List<XpVehicleModel> vehicleModels = listR.getData();
+                Map<String, XpVehicleModel> vehicleModelMap = new HashMap<>();
+                for (XpVehicleModel vehicleModel : vehicleModels) {
+                    vehicleModelMap.put(vehicleModel.getId().toString(), vehicleModel);
+                }
+                for (PricingPageListVO record : page.getRecords()) {
+                    XpVehicleModel xpVehicleModel = vehicleModelMap.get(record.getVehicleModel());
+                    if(xpVehicleModel != null){
+                        record.setVehicleModelName(xpVehicleModel.getName());
+                    }
+                }
+            }
+        }
         return pageInfo;
     }
 
     @Override
-    public void add(PricingAddDTO dto) {
+    public Long add(PricingAddDTO dto) {
         XpOpenCity openCity = xpOpenCityMapper.selectById(dto.getCityId());
         if (openCity == null) {
             throw new ServiceException("开通城市不存在");
@@ -646,7 +736,7 @@
         XpPricing pricing = new XpPricing();
         pricing.setVehicleModel(dto.getVehicleModel());
         pricing.setChannel(dto.getChannel());
-        pricing.setCityId(dto.getCityId().intValue());
+        pricing.setCityId(dto.getCityId());
         pricing.setRemark(dto.getRemark());
         pricing.setPricingType(dto.getPricingType());
         pricing.setBasicPricingJson("{}");
@@ -654,6 +744,30 @@
         pricing.setDynamicPricingJson("{}");
         pricing.setIsDynamicPrice(0);
         this.save(pricing);
+        return pricing.getId();
+    }
+
+    @Override
+    public Long edit(PricingEditDTO dto) {
+        //1.查询定价
+        XpPricing pricing = getById(dto.getId());
+        if (Objects.nonNull(pricing)) {
+            LambdaUpdateWrapper<XpPricing> updateWrapper = new LambdaUpdateWrapper<>();
+            //2.判断定价类型是否改变
+            if (!pricing.getPricingType().equals(dto.getPricingType())) {
+                updateWrapper.set(XpPricing::getBasicPricingJson, null);
+                updateWrapper.set(XpPricing::getStartingFareJson, null);
+                updateWrapper.set(XpPricing::getDynamicPricingJson, null);
+            }
+            updateWrapper.set(XpPricing::getVehicleModel, dto.getVehicleModel());
+            updateWrapper.set(XpPricing::getChannel, dto.getChannel());
+            updateWrapper.set(XpPricing::getCityId, dto.getCityId());
+            updateWrapper.set(StringUtils.isNotBlank(dto.getRemark()), XpPricing::getRemark, dto.getRemark());
+            updateWrapper.set(XpPricing::getPricingType, dto.getPricingType());
+            updateWrapper.eq(XpPricing::getId, dto.getId());
+            update(updateWrapper);
+        }
+        return dto.getId();
     }
 
     @Override
@@ -662,11 +776,16 @@
         if (pricing == null) {
             throw new ServiceException("定价不存在", I18nKeyConstant.PRICING_NOT_EXIST);
         }
-
         try {
-            JSONObject.parseObject(dto.getBasicPricingJson());
-            JSONArray.parseArray(dto.getStartingFareJson());
-            JSONObject.parseObject(dto.getDynamicPricingJson());
+            if (StringUtils.isNotBlank(dto.getBasicPricingJson())) {
+                JSONObject.parseObject(dto.getBasicPricingJson());
+            }
+            if (StringUtils.isNotBlank(dto.getStartingFareJson())) {
+                JSONArray.parseArray(dto.getStartingFareJson());
+            }
+            if (StringUtils.isNotBlank(dto.getDynamicPricingJson())) {
+                JSONObject.parseObject(dto.getDynamicPricingJson());
+            }
         } catch (Exception e) {
             throw new ServiceException("价格配置JSON格式不正确", I18nKeyConstant.PRICING_JSON_INVALID);
         }
@@ -674,9 +793,32 @@
         XpPricing update = new XpPricing();
         update.setId(dto.getId());
         update.setBasicPricingJson(dto.getBasicPricingJson());
-        update.setStartingFareJson(dto.getStartingFareJson());
+        update.setStartingFareJson(StringUtils.isNotBlank(dto.getStartingFareJson()) ? dto.getStartingFareJson() : null);
         update.setDynamicPricingJson(dto.getDynamicPricingJson());
+        update.setIsDynamicPrice(dto.getIsDynamicPrice());
         this.updateById(update);
+
+        // 动态调价 Quartz 任务调度
+        String jobName = DynamicPricingCheckJob.JOB_PREFIX + dto.getId();
+        if (Integer.valueOf(1).equals(dto.getIsDynamicPrice())
+                && StringUtils.isNotBlank(dto.getDynamicPricingJson())) {
+            JSONObject dynamicJson = JSONObject.parseObject(dto.getDynamicPricingJson());
+            Integer periodMinutes = dynamicJson.getInteger("num1");
+            if (periodMinutes != null && periodMinutes > 0) {
+                // 先移除可能存在的旧任务,再注册新任务(num1 分钟后首次执行)
+                QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
+                Date triggerTime = new Date(System.currentTimeMillis() + periodMinutes * 60_000L);
+                Map<String, Object> jobData = new HashMap<>();
+                jobData.put("pricingId", dto.getId());
+                QuartzManager.addJob(DynamicPricingCheckJob.class, jobName,
+                        TimeJobType.DYNAMIC_PRICING_CHECK, triggerTime, jobData);
+                log.info("动态调价任务已注册 pricingId={}, 供需计算周期={}分钟", dto.getId(), periodMinutes);
+            }
+        } else {
+            // 关闭动态调价时,移除已存在的任务
+            QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
+            log.info("动态调价任务已移除 pricingId={}", dto.getId());
+        }
     }
 
     @Override
@@ -692,4 +834,80 @@
         this.updateById(update);
     }
 
+
+    @Override
+    public void savePrice(PricingInfoVo dto, XpOfficialPartner officialPartner) {
+        XpOpenCity openCity = xpOpenCityMapper.selectOne(new QueryWrapper<XpOpenCity>().eq("city_code", dto.getCityCode()));
+        if (openCity == null) {
+            throw new ServiceException("城市未开通");
+        }
+
+        XpPricing pricing = this.lambdaQuery()
+                .eq(XpPricing::getVehicleModel, dto.getVehicleModel())
+                .eq(XpPricing::getChannel, officialPartner.getBrandName())
+                .eq(XpPricing::getCityId, openCity.getId().intValue())
+                .eq(XpPricing::getOfficialPartnerId, officialPartner.getId())
+                .one();
+
+        if(null == pricing){
+            pricing = new XpPricing();
+            pricing.setOfficialPartnerId(officialPartner.getId());
+            pricing.setVehicleModel(dto.getVehicleModel());
+            pricing.setChannel(officialPartner.getBrandName());
+            pricing.setCityId(openCity.getId());
+            pricing.setRemark(dto.getRemark());
+            pricing.setPricingType(dto.getPricingType());
+            pricing.setBasicPricingJson("{}");
+            pricing.setStartingFareJson("[]");
+            pricing.setDynamicPricingJson("{}");
+            pricing.setIsDynamicPrice(0);
+            this.save(pricing);
+        }
+
+        try {
+            if (StringUtils.isNotBlank(dto.getBasicPricingJson())) {
+                JSONObject.parseObject(dto.getBasicPricingJson());
+            }
+            if (StringUtils.isNotBlank(dto.getStartingFareJson())) {
+                JSONArray.parseArray(dto.getStartingFareJson());
+            }
+            if (StringUtils.isNotBlank(dto.getDynamicPricingJson())) {
+                JSONObject.parseObject(dto.getDynamicPricingJson());
+            }
+        } catch (Exception e) {
+            throw new ServiceException("价格配置JSON格式不正确", I18nKeyConstant.PRICING_JSON_INVALID);
+        }
+
+        XpPricing update = new XpPricing();
+        update.setId(pricing.getId());
+        update.setBasicPricingJson(dto.getBasicPricingJson());
+        update.setStartingFareJson(StringUtils.isNotBlank(dto.getStartingFareJson()) ? dto.getStartingFareJson() : null);
+        update.setDynamicPricingJson(dto.getDynamicPricingJson());
+        update.setIsDynamicPrice(dto.getIsDynamicPrice());
+        update.setPriceRule(dto.getPriceRule());
+        this.updateById(update);
+
+        // 动态调价 Quartz 任务调度
+        String jobName = DynamicPricingCheckJob.JOB_PREFIX + pricing.getId();
+        if (Integer.valueOf(1).equals(dto.getIsDynamicPrice())
+                && StringUtils.isNotBlank(dto.getDynamicPricingJson())) {
+            JSONObject dynamicJson = JSONObject.parseObject(dto.getDynamicPricingJson());
+            Integer periodMinutes = dynamicJson.getInteger("num1");
+            if (periodMinutes != null && periodMinutes > 0) {
+                // 先移除可能存在的旧任务,再注册新任务(num1 分钟后首次执行)
+                QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
+                Date triggerTime = new Date(System.currentTimeMillis() + periodMinutes * 60_000L);
+                Map<String, Object> jobData = new HashMap<>();
+                jobData.put("pricingId", pricing.getId());
+                QuartzManager.addJob(DynamicPricingCheckJob.class, jobName,
+                        TimeJobType.DYNAMIC_PRICING_CHECK, triggerTime, jobData);
+                log.info("动态调价任务已注册 pricingId={}, 供需计算周期={}分钟", pricing.getId(), periodMinutes);
+            }
+        } else {
+            // 关闭动态调价时,移除已存在的任务
+            QuartzManager.removeJob(jobName, TimeJobType.DYNAMIC_PRICING_CHECK);
+            log.info("动态调价任务已移除 pricingId={}", pricing.getId());
+        }
+
+    }
 }

--
Gitblit v1.7.1