package com.xiaopeng.order.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 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.google.common.collect.ImmutableMap; import com.xiaopeng.api.dto.account.GetUserCouponDto; import com.xiaopeng.api.dto.account.UseUserCouponDto; import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.order.GetOrderNumDto; import com.xiaopeng.api.dto.order.HistoryEndPointsDto; import com.xiaopeng.api.dto.order.HistoryStartPointsDto; import com.xiaopeng.api.dto.order.PopOrderDto; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.dto.statistics.DailyCountDTO; import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.feignClient.account.XpAppUserClient; import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; import com.xiaopeng.api.feignClient.operation.XpPointClient; import com.xiaopeng.api.feignClient.operation.XpPricingClient; import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.account.XpAppUser; import com.xiaopeng.api.model.operation.XpFeedbackType; import com.xiaopeng.api.model.operation.XpGeoQueryEntity; import com.xiaopeng.api.model.operation.XpPoint; import com.xiaopeng.api.model.operation.XpPricing; import com.xiaopeng.api.model.order.*; import com.xiaopeng.api.model.vehicleConvoy.XpFleet; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.account.UserCouponVo; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType; import com.xiaopeng.api.vo.order.*; import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; 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.enums.OrderStatusEnum; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; 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; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.common.security.utils.SecurityUtils; import com.xiaopeng.order.constant.I18nKeyConstant; import com.xiaopeng.order.dto.MileageDto; import com.xiaopeng.order.job.base.QuartzManager; import com.xiaopeng.order.job.base.TimeJobType; import com.xiaopeng.order.job.jobs.EndTripJob; import com.xiaopeng.order.job.jobs.OrderCancelJob; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.mangodb.service.OrderTrajectoryService; import com.xiaopeng.order.mapper.XpCruiseOrderMapper; import com.xiaopeng.order.mapper.XpOrderDetailMapper; import com.xiaopeng.order.mapper.XpOrderMapper; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.query.XpCruiseOrderPageQuery; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; import com.xiaopeng.order.model.query.XpOrderPageQuery; import com.xiaopeng.order.model.vo.*; import com.xiaopeng.order.service.*; import com.xiaopeng.order.utils.TaxiPricingDemoService; import com.xiaopeng.order.utils.TrajectoryGenerator; import com.xiaopeng.order.utils.holiday.HolidayUtil; import com.xiaopeng.order.vo.OrderDetailVo; 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; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.*; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; /** *

* 订单 服务实现类 *

* * @author mitao * @since 2026-02-03 */ @Slf4j @Service @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruiseOrderServiceImpl extends ServiceImpl implements IXpCruiseOrderService { private final XpVehicleClient xpVehicleClient; private final XpFleetVehicleClient xpFleetVehicleClient; private final XpFleetClient xpFleetClient; /** * 关闭当前巡游单子 * @param vin */ @Override public String updateCruiseOrder(String vin) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper().eq(XpCruiseOrder::getVehicleVin, vin).eq(XpCruiseOrder::getStatus, 1); XpCruiseOrder xpCruiseOrder = this.getOne(wrapper); if (xpCruiseOrder != null) { xpCruiseOrder.setStatus(2); this.update(xpCruiseOrder, wrapper); return xpCruiseOrder.getId(); } return null; } @Override public String closeCruiseOrder(String vin) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper().eq(XpCruiseOrder::getVehicleVin, vin).eq(XpCruiseOrder::getStatus, 1); XpCruiseOrder xpCruiseOrder = this.getOne(wrapper); if (xpCruiseOrder != null) { xpCruiseOrder.setStatus(3); this.update(xpCruiseOrder, wrapper); return xpCruiseOrder.getId(); } return null; } @Override public PageInfo pageList(XpCruiseOrderPageQuery query) { PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(XpCruiseOrder::getMissionId, String.valueOf(query.getMissionId())) .like(StringUtils.isNotBlank(query.getOrderNumber()), XpCruiseOrder::getOrderNumber, query.getOrderNumber()) .eq(query.getStatus() != null, XpCruiseOrder::getStatus, query.getStatus()); if (query.getStartTime() != null) { wrapper.ge(BaseModel::getCreateTime, query.getStartTime().atStartOfDay()); } if (query.getEndTime() != null) { wrapper.le(BaseModel::getCreateTime, query.getEndTime().plusDays(1).atStartOfDay()); } if (query.getFleetId() != null) { R> fleetVehicleResult = xpFleetVehicleClient.listVehicleIdsByFleetId(query.getFleetId()); if (fleetVehicleResult == null || CollectionUtils.isEmpty(fleetVehicleResult.getData())) { pageInfo.setRecords(Collections.emptyList()); return pageInfo; } wrapper.in(XpCruiseOrder::getVehicleId, fleetVehicleResult.getData()); } if (StringUtils.isNotBlank(query.getPlateNumber())) { R> vehicleResult = xpVehicleClient.listByPlateNumber(query.getPlateNumber()); if (vehicleResult == null || CollectionUtils.isEmpty(vehicleResult.getData())) { pageInfo.setRecords(Collections.emptyList()); return pageInfo; } List vehicleIds = vehicleResult.getData().stream().map(XpVehicle::getId).collect(Collectors.toList()); wrapper.in(XpCruiseOrder::getVehicleId, vehicleIds); } wrapper.orderByDesc(BaseModel::getCreateTime); Page page = new Page<>(query.getPageNum(), query.getPageSize()); Page pageResult = this.page(page, wrapper); if (CollectionUtils.isEmpty(pageResult.getRecords())) { pageInfo.setTotal(0L); pageInfo.setRecords(Collections.emptyList()); return pageInfo; } Set vehicleIds = pageResult.getRecords().stream() .map(XpCruiseOrder::getVehicleId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Map vehicleMap; if (!vehicleIds.isEmpty()) { R> vehicleResult = xpVehicleClient.listByIds(new ArrayList<>(vehicleIds)); if (vehicleResult != null && !CollectionUtils.isEmpty(vehicleResult.getData())) { vehicleMap = vehicleResult.getData().stream().collect(Collectors.toMap(XpVehicle::getId, v -> v)); } else { vehicleMap = Collections.emptyMap(); } } else { vehicleMap = Collections.emptyMap(); } Map vehicleFleetIdMap = new HashMap<>(); if (!vehicleIds.isEmpty()) { for (Long vehicleId : vehicleIds) { R fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(vehicleId); if (fleetIdResult != null && fleetIdResult.getData() != null) { vehicleFleetIdMap.put(vehicleId, fleetIdResult.getData()); } } } Map fleetNameMap; if (!vehicleFleetIdMap.isEmpty()) { List fleetIds = vehicleFleetIdMap.values().stream().distinct().collect(Collectors.toList()); R> fleetResult = xpFleetClient.listByIds(fleetIds); if (fleetResult != null && !CollectionUtils.isEmpty(fleetResult.getData())) { fleetNameMap = fleetResult.getData().stream() .collect(Collectors.toMap(XpFleet::getId, XpFleet::getFleetName, (a, b) -> a)); } else { fleetNameMap = Collections.emptyMap(); } } else { fleetNameMap = Collections.emptyMap(); } List voList = pageResult.getRecords().stream().map(order -> { XpCruiseOrderPageVO vo = new XpCruiseOrderPageVO(); BeanUtils.copyProperties(order, vo); XpVehicle vehicle = vehicleMap.get(order.getVehicleId()); if (vehicle != null) { vo.setPlateNumber(vehicle.getPlateNumber()); } Long fleetId = vehicleFleetIdMap.get(order.getVehicleId()); if (fleetId != null) { vo.setFleetName(fleetNameMap.get(fleetId)); } return vo; }).collect(Collectors.toList()); pageInfo.setTotal(pageResult.getTotal()); pageInfo.setRecords(voList); return pageInfo; } }