| | |
| | | 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; |
| | | import com.xiaopeng.api.dto.map.RouteAndFareDto; |
| | | 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.feignClient.vehicleConvoy.XpVehicleClient; |
| | | 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.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.account.UserCouponVo; |
| | | import com.xiaopeng.api.vo.operation.FareVo; |
| | | import com.xiaopeng.api.vo.operation.RouteAndFareVo; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.api.vo.order.XpPricingCardVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | 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.XpOrderDto; |
| | | import com.xiaopeng.operation.entity.XpGeoQueryEntity; |
| | | 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.XpPricingCardVo; |
| | | 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; |
| | | |
| | | 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; |
| | |
| | | * @author liu |
| | | * @since 2026-02-03 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class XpPricingServiceImpl extends ServiceImpl<XpPricingMapper, XpPricing> implements XpPricingService { |
| | | |
| | |
| | | @Resource |
| | | private XpElectronicFenceAreaMapper xpElectronicFenceAreaMapper; |
| | | |
| | | @Resource |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Resource |
| | | private XpPointMapper xpPointMapper; |
| | | |
| | | private XpVehicleModelClient xpVehicleModelClient; |
| | | @Resource |
| | | private XpWhitelistMapper xpWhitelistMapper; |
| | | |
| | |
| | | |
| | | @Autowired |
| | | private XpElectronicFenceMapper xpElectronicFenceMapper; |
| | | |
| | | @Autowired |
| | | private XpPointService xpPointService; |
| | | |
| | | @Resource(name = "hutoolSnowflake") |
| | | private Snowflake snowflake; |
| | | |
| | | |
| | | // 自定义线程池用于并行执行任务 |
| | |
| | | |
| | | |
| | | @Override |
| | | @Deprecated |
| | | public RouteAndFareVo getRouteAndFare(RouteAndFareDto routeAndFareDto, String userId) { |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | 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. 并行执行远程服务调用 判断是否同一经营区域 |
| | | CompletableFuture<R<Boolean>> diagnosisAreaFuture = CompletableFuture.supplyAsync( |
| | |
| | | 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 |
| | |
| | | |
| | | // 4. 等待所有并行任务完成并获取结果 |
| | | R<Boolean> diagnosisResult = diagnosisAreaFuture.join(); |
| | | // R<RouteVo> routeResult = routeFuture.join(); |
| | | R<UserCouponVo> couponResult = couponFuture.join(); |
| | | |
| | | // 5. 处理诊断结果 |
| | |
| | | throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | } |
| | | |
| | | // 6. 处理路线结果 |
| | | // // 6. 处理路线结果 |
| | | // if (routeResult.getCode() != 200) { |
| | | // throw new RuntimeException(routeResult.getMsg()); |
| | | // } |
| | |
| | | } 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) { |
| | |
| | | |
| | | // 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 { |
| | |
| | | } |
| | | |
| | | // 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并缓存 |
| | |
| | | return 1; |
| | | } else { |
| | | // 已完成接单的数据 |
| | | List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() > 1).collect(Collectors.toList()); |
| | | List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() == 1).collect(Collectors.toList()); |
| | | |
| | | // 计算平均等待时间 |
| | | OptionalDouble averageOptional = validEntities.stream().mapToDouble(XpGeoQueryEntity::getSeconds).average(); |
| | |
| | | double waitMinutes = (average * count) / 60; |
| | | if (waitMinutes > 3) { |
| | | throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME); |
| | | } else if (waitMinutes == 0) { |
| | | return 1; |
| | | } |
| | | return (int) waitMinutes; |
| | | } |
| | |
| | | |
| | | @Override |
| | | public Long saveOrder(XpOrderDto dto, String uid) { |
| | | |
| | | // 是否在运营区域时间内 |
| | | XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(dto.getXpElectronicFenceAreaId()); |
| | | XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceArea.getElectronicId()); |
| | |
| | | // 判断是否有进行的订单 |
| | | 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); |
| | | if (cancelOrder != null) { |
| | | Integer num = Integer.valueOf(cancelOrder.toString()); |
| | | if (num >= cancelCount) { |
| | | return 0l; |
| | | } |
| | | // 判断点位是否在运营区域内 |
| | | 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; |
| | | Integer num = xpOrderClient.todayCancellationCount(Long.valueOf(uid)).getData(); |
| | | if (num >= cancelCount) { |
| | | isSilent = true; |
| | | } |
| | | |
| | | |
| | | // 获取起步里程 |
| | | 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获取手机号 |
| | | |
| | | 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(); |
| | | |
| | | xpOrder.setStartMileage(Double.valueOf(startMileage)); |
| | | xpOrder.setVehicleId(1l); |
| | | |
| | | // 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()); |
| | |
| | | xpOrder.setEndPointId(dto.getEndPointId()); |
| | | xpOrder.setStartPointName(xpPoint.getPointName()); |
| | | xpOrder.setEndPointName(endXpPoint.getPointName()); |
| | | xpOrder.setXpuStartTaskId(snowflake.nextId() + ""); |
| | | xpOrder.setXpuEndTaskId(snowflake.nextId() + ""); |
| | | |
| | | // 当前时段 |
| | | String currentTimeSlot = DateUtils.getCurrentTimeSlot(); |
| | |
| | | Integer distance = 0; |
| | | Integer duration = 0; |
| | | if (distanceAndDuration.getCode() != 200) { |
| | | //静默处理 |
| | | return 0l; |
| | | // throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); |
| | | } |
| | | distance = distanceAndDuration.getData().getDistance(); |
| | | duration = distanceAndDuration.getData().getDuration(); |
| | | // distance = distanceAndDuration.getData().getDistance(); |
| | | // duration = distanceAndDuration.getData().getDuration(); |
| | | |
| | | |
| | | // 产生订单 |
| | |
| | | throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); |
| | | } |
| | | Long orderId = addOrderR.getData(); |
| | | |
| | | // 静默处理 不推单 |
| | | if (isSilent) { |
| | | return orderId; |
| | | } |
| | | |
| | | // 最大距离 |
| | | Object maxPushDistanceObj = redisService.getCacheObject(CacheConstants.MAX_PUSH_DISTANCE); |
| | | Double maxPushDistance = 0.0; |
| | |
| | | // 尾部 |
| | | redisService.addToTail(s, orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule()); |
| | | } |
| | | xpOrder.setQueueName(s); |
| | | xpOrderClient.updateOrder(xpOrder); |
| | | |
| | | // 存储mongodb 数据 |
| | | XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity(); |
| | | xpGeoQueryEntity.setOrderId(orderId.toString()); |
| | | xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(), xpPoint.getPointLat())); |
| | | // 计算2个时间的秒数 |
| | | xpGeoQueryEntity.setTime(currentTimeSlot); |
| | | xpGeoQueryEntity.setStatus(0); |
| | | xpGeoQueryEntity.setTimestamp(System.currentTimeMillis()); |
| | | geoQueryEntityService.save(xpGeoQueryEntity); |
| | | |
| | | return orderId; |
| | | } |
| | | } |
| | | |
| | | String key = CacheConstants.QUEUE_POINT_ID + "-" + xpPoint.getId() + "-" + xpPoint.getPointLon() + "," + xpPoint.getPointLat(); |
| | | redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule())); |
| | | xpOrder.setQueueName(key); |
| | | xpOrderClient.updateOrder(xpOrder); |
| | | |
| | | |
| | | // 存储mongodb 数据 |
| | | XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity(); |
| | | xpGeoQueryEntity.setOrderId(orderId.toString()); |
| | | xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(), xpPoint.getPointLat())); |
| | | // 计算2个时间的秒数 |
| | | xpGeoQueryEntity.setTime(currentTimeSlot); |
| | | xpGeoQueryEntity.setStatus(0); |
| | | xpGeoQueryEntity.setTimestamp(System.currentTimeMillis()); |
| | | geoQueryEntityService.save(xpGeoQueryEntity); |
| | | |
| | | return orderId; |
| | | |
| | | // |
| | |
| | | |
| | | } |
| | | |
| | | |
| | | 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); |
| | |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<PricingPageListVO> pageList(PricingPageListQuery query) { |
| | | PageInfo<PricingPageListVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | 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 Long add(PricingAddDTO dto) { |
| | | XpOpenCity openCity = xpOpenCityMapper.selectById(dto.getCityId()); |
| | | if (openCity == null) { |
| | | throw new ServiceException("开通城市不存在"); |
| | | } |
| | | |
| | | Long count = this.lambdaQuery() |
| | | .eq(XpPricing::getVehicleModel, dto.getVehicleModel()) |
| | | .eq(XpPricing::getChannel, dto.getChannel()) |
| | | .eq(XpPricing::getCityId, dto.getCityId().intValue()) |
| | | .count(); |
| | | if (count != null && count > 0) { |
| | | throw new ServiceException("该车型/渠道/城市的定价已存在", I18nKeyConstant.PRICING_EXISTS); |
| | | } |
| | | |
| | | XpPricing pricing = new XpPricing(); |
| | | pricing.setVehicleModel(dto.getVehicleModel()); |
| | | pricing.setChannel(dto.getChannel()); |
| | | pricing.setCityId(dto.getCityId()); |
| | | pricing.setRemark(dto.getRemark()); |
| | | pricing.setPricingType(dto.getPricingType()); |
| | | pricing.setBasicPricingJson("{}"); |
| | | pricing.setStartingFareJson("[]"); |
| | | 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 |
| | | public void setPrice(PricingSetPriceDTO dto) { |
| | | XpPricing pricing = this.getById(dto.getId()); |
| | | if (pricing == null) { |
| | | throw new ServiceException("定价不存在", I18nKeyConstant.PRICING_NOT_EXIST); |
| | | } |
| | | 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(dto.getId()); |
| | | update.setBasicPricingJson(dto.getBasicPricingJson()); |
| | | 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 |
| | | public void setRule(PricingSetRuleDTO dto) { |
| | | XpPricing pricing = this.getById(dto.getId()); |
| | | if (pricing == null) { |
| | | throw new ServiceException("定价不存在", I18nKeyConstant.PRICING_NOT_EXIST); |
| | | } |
| | | |
| | | XpPricing update = new XpPricing(); |
| | | update.setId(dto.getId()); |
| | | update.setPriceRule(dto.getPriceRule()); |
| | | 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()); |
| | | } |
| | | |
| | | } |
| | | } |