package com.sckw.transport.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.model.base.BaseModel;
import com.sckw.core.model.enums.AddressTypeEnum;
import com.sckw.core.model.enums.CarWaybillEnum;
import com.sckw.core.model.enums.CarWaybillV1Enum;
import com.sckw.core.utils.DateUtils;
import com.sckw.core.utils.LocUtils;
import com.sckw.core.web.constant.CommonConstants;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.BaseIotResult;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.fleet.api.model.vo.RDriverVo;
import com.sckw.fleet.api.model.vo.RFleetDriverVo;
import com.sckw.fleet.api.model.vo.RFleetVo;
import com.sckw.fleet.api.model.vo.RTruckVo;
import com.sckw.manage.api.RemoteManageService;
import com.sckw.order.api.dubbo.RemoteTradeOrderAmountService;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.payment.api.dubbo.PaymentDubboService;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.KwsEnterpriseResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.transport.api.model.vo.RWaybillOrderVo;
import com.sckw.transport.common.config.UrlConfigProperties;
import com.sckw.transport.dao.KwtWaybillOrderSubtaskMapper;
import com.sckw.transport.model.*;
import com.sckw.transport.model.dto.TruckDto;
import com.sckw.transport.api.feign.VehicleTraceClient;
import com.sckw.transport.api.model.dto.VehicleDataDTO;
import com.sckw.transport.api.model.dto.VehicleReturnData;
import com.sckw.transport.model.enuma.VehicleExceptionTypeEnum;
import com.sckw.transport.model.param.*;
import com.sckw.transport.model.dto.GenerateTraceReq;
import com.sckw.transport.model.vo.CurrentTaskTraceReqVo;
import com.sckw.transport.model.vo.KwfTruckTraceReplayVo;
import com.sckw.transport.model.vo.TruckInfoVo;
import com.sckw.transport.model.vo.TruckSelectVo;
import com.sckw.transport.model.dto.TruckSelectReq;
import com.sckw.transport.model.dto.MapVehicleQueryReq;
import com.sckw.transport.model.vo.MapVehicleVo;
import com.sckw.transport.model.enuma.MapVehicleSortTypeEnum;
import com.sckw.transport.repository.*;
import com.sckw.transport.response.CollectZjxlResponse;
import com.sckw.transport.service.zj.VehicleCollectService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.misc.Array2DHashSet;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.Data;
import org.springframework.transaction.annotation.Transactional;


/**
 * @author PC
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class kwfTruckTraceService {
    private final KwtWaybillOrderRepository kwtWaybillOrderRepository;
    private final KwtWaybillOrderAddressRepository kwtWaybillOrderAddressRepository;
    private final UrlConfigProperties urlConfigProperties;
    private final KwtWaybillOrderSubtaskRepository kwtWaybillOrderSubtaskRepository;
    private final VehicleCollectService vehicleCollectService;
    private final KwtLogisticsOrderUnitRepository kwtLogisticsOrderUnitRepository;
    private final VehicleTraceClient vehicleTraceClient;
    private final KwtLogisticsOrderGoodsRepository kwtLogisticsOrderGoodsRepository;
    private final KwtLogisticsOrderRepository kwtLogisticsOrderRepository;
    private final KwtVehicleExceptionRepository kwtVehicleExceptionRepository;
    private final KwtWaybillOrderSubtaskMapper waybillOrderSubtaskDao;;
    private final KwtLogisticsOrderAddressRepository kwtLogisticsOrderAddressRepository;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    RemoteSystemService remoteSystemService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    TradeOrderInfoService tradeOrderInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    RemoteTradeOrderAmountService tradeOrderAmountService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    GoodsInfoService goodsInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    RemoteFleetService fleetService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    RemoteContractService remoteContractService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    RemoteManageService remoteManageService;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    PaymentDubboService paymentDubboService ;

    public PageDataResult<KwfTruckTraceReplayVo> findPage(KwfTruckTraceReplayReq req) {
        log.info("查询历轨迹回放参数：{}", req);

        Date startDate = getStartDate(req.getStartTime());
        Date endDate = getEndDate(req.getEndTime());
        // 前置条件：根据承运单位和托运单位筛选出符合条件的运单ID
        MapVehicleQueryReq queryReq = new MapVehicleQueryReq();
        queryReq.setCarrierEntId(req.getCarrierEntId());
        queryReq.setLogisticOrderNo(req.getLogisticOrderNo());
        Set<Long> entList = new HashSet<>();
        entList.add(LoginUserHolder.getEntId());
        Set<Long> wayOrderIds = getWayOrderIds(queryReq,entList);
        if (CollectionUtils.isEmpty(wayOrderIds) && (StringUtils.isNotBlank(req.getLogisticOrderNo()) || Objects.nonNull(req.getCarrierEntId()) || Objects.nonNull(LoginUserHolder.getEntId()))) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        Page<KwtWaybillOrder> page = kwtWaybillOrderRepository.findPage(wayOrderIds,req.getTruckNo(),req.getPageNum(), req.getPageSize(), startDate, endDate);
        List<KwtWaybillOrder> records = page.getRecords();
        if(CollectionUtils.isEmpty(page.getRecords())) {
            return PageDataResult.success(req.getPageNum(), req.getPageSize(),0L, null);
        }
        //查询企业 获取承运单位
        List<Long> entIds = records.stream().map(KwtWaybillOrder::getEntId).distinct().collect(Collectors.toList());
        //运单id
        List<Long> wOrderIds = records.stream().map(KwtWaybillOrder::getId).collect(Collectors.toList());
        //通过运单号查询订单
        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = kwtWaybillOrderSubtaskRepository.queryByWOrderIds(wOrderIds);

        //关联订单id
        Set<Long>  lOrderIds = null;
        //订单号映射订单对象
        Map<String, KwtWaybillOrderSubtask> worderNoAndWorderMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(waybillOrderSubtasks)){
            lOrderIds = waybillOrderSubtasks.stream().map(KwtWaybillOrderSubtask::getLOrderId).collect(Collectors.toSet());
            worderNoAndWorderMap = waybillOrderSubtasks.stream()
                    .collect(Collectors.toMap(KwtWaybillOrderSubtask::getWOrderNo, Function.identity(), (k1, k2) -> k1));
        }
        List<KwtLogisticsOrderUnit> logisticsOrderUnits = Lists.newArrayList();
        Map<Long, KwtLogisticsOrder> logisticsOrderMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(lOrderIds)){
            //查询物流订单
            List<KwtLogisticsOrder> logisticsOrders = kwtLogisticsOrderRepository.queryByLogisticsOrderIds(new ArrayList<>(lOrderIds));
            logisticsOrderMap = Optional.ofNullable(logisticsOrders)
                    .orElse(List.of())
                    .stream()
                    .collect(Collectors.toMap(KwtLogisticsOrder::getId, Function.identity(), (k1, k2) -> k1));
            logisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByLOrderIdsAndUnitType(lOrderIds,2);
        }


        //物流订单id映射企业
        Map<Long, KwtLogisticsOrderUnit> lOrderIdAndLogisticsOrderUnitMap = logisticsOrderUnits.stream()
                .collect(Collectors.toMap(KwtLogisticsOrderUnit::getLOrderId, Function.identity(), (k1, k2) -> k1));
        //通过企业id映射企业信息
        Map<Long, KwsEnterpriseResDto> idAndKwsEnterpriseMap = remoteSystemService.queryEnterpriseByEntIds(entIds);

        //装货地址和卸货地址 kwt_waybill_order_address
        List<KwtWaybillOrderAddress> orderAddresses = kwtWaybillOrderAddressRepository.queryBywOrderIds(wOrderIds);

        //运单id和状态组合key映射地址
        Map<Long, List<KwtWaybillOrderAddress>> wOrderIdAndAddressMap = orderAddresses.stream()
                .collect(Collectors.groupingBy(KwtWaybillOrderAddress::getWOrderId));

        // 批量查询运单轨迹数据，统计异常数量（通过alarmCode判断）
        List<String> wOrderNos = records.stream()
                .map(KwtWaybillOrder::getWOrderNo)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        // 批量查询每个运单的轨迹数据
        Map<String, Integer> exceptionCountMap = Maps.newHashMap();
        Map<String,List<VehicleReturnData>> traceMap = Maps.newHashMap();
        getTraceInfoList(wOrderNos, traceMap, exceptionCountMap);

        // Map<String, Integer> exceptionCountMap = countExceptionsByTraceData(wOrderNos);
        Map<String, KwtWaybillOrderSubtask> finalWorderNoAndWorderMap = worderNoAndWorderMap;
        Map<Long, KwtLogisticsOrder> finalLogisticsOrderMap = logisticsOrderMap;
        List<KwfTruckTraceReplayVo> kwfTruckTraceReplayVoList = records.stream()
                .map(r -> getKwfTruckTraceReplayVo(r, idAndKwsEnterpriseMap, wOrderIdAndAddressMap,
                        lOrderIdAndLogisticsOrderUnitMap, finalWorderNoAndWorderMap,
                        exceptionCountMap, finalLogisticsOrderMap,traceMap))
                .collect(Collectors.toList());
        // 根据排序类型进行排序
        MapVehicleSortTypeEnum sortType = MapVehicleSortTypeEnum.getByCode(req.getSortType());
        kwfTruckTraceReplayVoList = switch (sortType) {
            case TIME_DESC ->
                // 按任务开始时间倒序
                    kwfTruckTraceReplayVoList.stream()
                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getTaskStartTime,
                                    Comparator.nullsLast(Comparator.reverseOrder())))
                            .collect(Collectors.toList());
            case DURATION_DESC ->
                // 按任务耗时倒序
                    kwfTruckTraceReplayVoList.stream()
                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getTaskDuration,
                                    Comparator.nullsLast(Comparator.reverseOrder())))
                            .collect(Collectors.toList());
            case EXCEPTION_COUNT_DESC ->
                // 按异常数量倒序
                    kwfTruckTraceReplayVoList.stream()
                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getExceptionCount,
                                    Comparator.nullsLast(Comparator.reverseOrder())))
                            .collect(Collectors.toList());
        };
       return PageDataResult.of(page,kwfTruckTraceReplayVoList);
    }

    private void getTraceInfoList(List<String> wOrderNos, Map<String,List<VehicleReturnData>> traceMap, Map<String, Integer> exceptionCountMap) {
        if (CollectionUtils.isNotEmpty(wOrderNos)) {
            for (String wOrderNo : wOrderNos) {
                try {
                    VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                    vehicleDataDTO.setWOrderNo(wOrderNo);

                    // 调用Feign接口查询轨迹列表
                    log.info("查询车辆数据中台请求轨迹数据：{}", JSON.toJSONString( vehicleDataDTO));
                    BaseIotResult<List<VehicleReturnData>> result =
                            vehicleTraceClient.queryVehicleDataList(vehicleDataDTO);
                    log.info("查询车辆数据中台响应轨迹数据：{}", JSON.toJSONString( result));
                    if (result != null && StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
                        List<VehicleReturnData> traceDataList = result.getData();
                        traceMap.put(wOrderNo, traceDataList);
                        // 统计alarmCode不为null且不为0的记录数量（表示有异常报警）
                        int exceptionCount = (int) traceDataList.stream()
                                .filter(data -> StringUtils.equals(data.getStatus(),"0"))
                                .count();

                        exceptionCountMap.put(wOrderNo, exceptionCount);
                        log.debug("运单号: {}, 异常数量: {}", wOrderNo, exceptionCount);
                    } else {
                        log.warn("查询运单轨迹数据失败或返回空数据, 运单号: {}", wOrderNo);
                        exceptionCountMap.put(wOrderNo, 0);
                    }
                } catch (Exception e) {
                    log.error("查询运单轨迹数据异常, 运单号: {}", wOrderNo, e);
                    exceptionCountMap.put(wOrderNo, 0);
                }
            }
        }
    }

    /**
     * 组织轨迹回访返回数据
     * @param waybillOrder 运单信息
     * @param idAndKwsEnterpriseMap 企业id映射企业信息map
     * @param wOrderIdAndAddressMap 运单id映射地址map
     * @return 轨迹回访返回数据
     */
    private static KwfTruckTraceReplayVo getKwfTruckTraceReplayVo(KwtWaybillOrder waybillOrder, Map<Long, KwsEnterpriseResDto> idAndKwsEnterpriseMap,
                                                                  Map<Long, List<KwtWaybillOrderAddress>> wOrderIdAndAddressMap
                                                                ,Map<Long, KwtLogisticsOrderUnit> lOrderIdAndLogisticsOrderUnitMap
                                                                ,Map<String, KwtWaybillOrderSubtask> worderNoAndWorderMap,
                                                                  Map<String, Integer> exceptionCountMap,
                                                                  Map<Long, KwtLogisticsOrder> logisticsOrderMap,
                                                                  Map<String,List<VehicleReturnData>> traceMap) {

        KwfTruckTraceReplayVo kwfTruckTraceReplay = new KwfTruckTraceReplayVo();
        kwfTruckTraceReplay.setOrderId(waybillOrder.getId());
        kwfTruckTraceReplay.setOrderNo(waybillOrder.getWOrderNo());
        kwfTruckTraceReplay.setDriverName(waybillOrder.getDriverName());
        kwfTruckTraceReplay.setPhone(waybillOrder.getDriverPhone());
        kwfTruckTraceReplay.setTruckNo(waybillOrder.getTruckNo());
        //已完成的状态
        List<Integer> complatedStatusList = Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode());
        if (complatedStatusList.contains(waybillOrder.getStatus())){
            kwfTruckTraceReplay.setStatus("1");
            kwfTruckTraceReplay.setStatusDesc("已结束");
            String endStartEndTime = DateUtils.format(waybillOrder.getUpdateTime(), DateUtils.DATE_TIME_PATTERN);
            kwfTruckTraceReplay.setTaskEndTime(StringUtils.equals(endStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: endStartEndTime);
        }else {
            kwfTruckTraceReplay.setStatus("0");
            kwfTruckTraceReplay.setStatusDesc("任务中");
            List<VehicleReturnData> data = traceMap.getOrDefault(waybillOrder.getWOrderNo(), new ArrayList<>());
            if (CollectionUtils.isNotEmpty(data)){
                VehicleReturnData vehicleReturnData = data.get(0);
                kwfTruckTraceReplay.setLatitude(vehicleReturnData.getLatitude());
                kwfTruckTraceReplay.setLongitude(vehicleReturnData.getLongitude());
                String endStartEndTime = DateUtils.format(vehicleReturnData.getTs(), DateUtils.DATE_TIME_PATTERN);
                kwfTruckTraceReplay.setTaskEndTime(StringUtils.equals(endStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: endStartEndTime);
            }

        }
        KwtWaybillOrderSubtask subtask = worderNoAndWorderMap.getOrDefault(waybillOrder.getWOrderNo(), new KwtWaybillOrderSubtask());
        kwfTruckTraceReplay.setRelationTaskNo(String.valueOf(subtask.getLOrderId()));
        KwtLogisticsOrder logisticsOrder = logisticsOrderMap.getOrDefault(subtask.getLOrderId(), new KwtLogisticsOrder());
        kwfTruckTraceReplay.setLogOrderNo(logisticsOrder.getLOrderNo());
        KwtLogisticsOrderUnit kwtLogisticsOrderUnit = lOrderIdAndLogisticsOrderUnitMap.getOrDefault(subtask.getLOrderId(), new KwtLogisticsOrderUnit());
        KwsEnterpriseResDto orDefault = idAndKwsEnterpriseMap.getOrDefault(kwtLogisticsOrderUnit.getEntId(), new KwsEnterpriseResDto());
        kwfTruckTraceReplay.setCarrier(orDefault.getFirmName());
        List<KwtWaybillOrderAddress> addressList = wOrderIdAndAddressMap.get(waybillOrder.getId());
        addressList.forEach(e -> {
            if (Objects.equals(e.getAddressType(), AddressTypeEnum.SHIPMENT.getCode())){
                kwfTruckTraceReplay.setStartAddress(e.getDetailAddress());
            }
            if (Objects.equals(e.getAddressType(),AddressTypeEnum.TAKE.getCode())){
                kwfTruckTraceReplay.setEndAddress(e.getDetailAddress());
            }
        });

        Date startTime =  waybillOrder.getCreateTime();
        String taskStartEndTime = DateUtils.format(startTime, DateUtils.DATE_TIME_PATTERN);
        kwfTruckTraceReplay.setTaskStartTime(StringUtils.equals(taskStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: taskStartEndTime);

        kwfTruckTraceReplay.setWarningCount("");
        // 从异常表查询该运单的异常数量
        Integer exceptionCount = exceptionCountMap.getOrDefault(waybillOrder.getWOrderNo(), 0);
        kwfTruckTraceReplay.setExceptionCount(exceptionCount);
        // 计算任务耗时（分钟）
        Date endTime = new Date();
        if (Objects.equals(waybillOrder.getStatus(), CarWaybillV1Enum.COMPLETED.getCode())){
            endTime = waybillOrder.getUpdateTime() != null ? waybillOrder.getUpdateTime() : new Date();
        }
        long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
        kwfTruckTraceReplay.setTaskDuration(duration);
        return kwfTruckTraceReplay;
    }

    /**
     * 查询车辆实时位置信息
     * @param req 查询参数
     * @return 车辆实时位置信息
     */
    public TruckInfoVo queryTruckInfo(TruckInfoReq req) {
        log.info("查询车辆实时位置信息参数：{}", req);
        //先查缓存 缓存没有 在查询数据中台 数据中台没有 则查询中交
        if (StringUtils.isNotBlank(req.getTruckId()) ){
            return getTruckInfo(req.getTruckId(),req.getOrderNo(),req.getTruckNo());
        }

        //如果车牌为空那么查询车队的第一条数据 （从tab页面直接进来）
        if (StringUtils.isNotBlank(req.getEntId())){
            RTruckVo dataFirstTruck = fleetService.findDataFirstTruck(Long.valueOf(req.getEntId()));
            if (Objects.isNull(dataFirstTruck) || Objects.isNull(dataFirstTruck.getTruckNo())){
                return new TruckInfoVo();
            }
            return getTruckInfo(req.getTruckId(),req.getOrderNo(),dataFirstTruck.getTruckNo());
        }
        return new TruckInfoVo();
    }

    private TruckInfoVo getTruckInfo(String truckId, String wOrderNo,String truckNo) {
        //先查询缓存 如果缓存没有就查数据中台 数据中台没有就查中交

        KwtWaybillOrder order = kwtWaybillOrderRepository.findOneByTruckId(truckId);
        if (Objects.isNull(order)){
            throw new BusinessException("该车辆运单信息不存在");
        }
        String location = RedissonUtils.getString(CommonConstants.TRUCK_LOCATION + truckId+CommonConstants.UNDERSCORE+order.getWOrderNo());
        if (StringUtils.isNotBlank(location)){
            TruckInfoVo truckDto = JSON.parseObject(location, TruckInfoVo.class);
            //如果运单号为空那么返回redis的数据 这个数据是app最后一次上报的数据
            if (Objects.nonNull(truckDto)){
                return truckDto;
               // return getTruckInfoVo(truckId, truckDto);
            }
        }

        //缓存没有则查询数据中台
        VehicleReturnData vehicleReturnData = getVehicleReturnData(truckId);
        if (Objects.nonNull(vehicleReturnData)){
           // saveRedisCache(truckId, wOrderNo, truckNo, vehicleReturnData);
            TruckInfoVo truckInfoVo = buildTruckInfo(truckId, vehicleReturnData, truckNo,order);
            RedissonUtils.putString(CommonConstants.TRUCK_LOCATION + truckId +CommonConstants.UNDERSCORE+ truckInfoVo.getOrderNo(), JSON.toJSONString(truckInfoVo),10,TimeUnit.DAYS);
            return truckInfoVo;
        }
        //todo 查询中交 如果数据中台没有数据则查询中交
       // return getTruckInfoVoByZj(truckNo, wOrderNo,truckId);
        return new TruckInfoVo();

    }


    private TruckInfoVo getTruckInfoVo(String truckId, TruckDto truckDto) {
        TruckInfoVo truckInfoVo = TruckInfoVo.toTruckInfoVo(truckDto);
        truckInfoVo.setGpsStatus(truckDto.getGpsStatus());
        truckInfoVo.setLongitude(truckDto.getLongitude());
        truckInfoVo.setLatitude(truckDto.getLatitude());
        truckInfoVo.setLocationTime(truckDto.getLocationTime());
        truckInfoVo.setTaskAddress(truckDto.getTaskAddress());
        KwtWaybillOrder order = kwtWaybillOrderRepository.findOneByTruckId(truckId);
        if (Objects.nonNull(order)){
            truckInfoVo.setTruckNo(order.getTruckNo());
            truckInfoVo.setOrderNo(order.getWOrderNo());
            truckInfoVo.setDriveId(String.valueOf(order.getDriverId()));
            truckInfoVo.setDriveName(order.getDriverName());
            truckInfoVo.setDrivePhone(order.getDriverPhone());
            truckInfoVo.setTruckId(truckId);
            truckInfoVo.setTaskStatus(String.valueOf(order.getStatus()));
        }

        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.findOneByWOrderNo(Optional.ofNullable(order)
                .map(KwtWaybillOrder::getWOrderNo).
                orElse( null));
        truckInfoVo.setLogicOrderNo(Objects.isNull(subtask) ? "" : String.valueOf(subtask.getLOrderId()));
        if (Objects.isNull(subtask)){
            return truckInfoVo;
        }
        truckInfoVo.setLogicOrderNo(String.valueOf(subtask.getLOrderId()));
        //根据物流订单号查询承运单位 2.代表承运企业
        KwtLogisticsOrderUnit kwtLogisticsOrderUnit = kwtLogisticsOrderUnitRepository.queryByLOrderIdAndUnitType(subtask.getLOrderId(), 2);
        if (Objects.nonNull(kwtLogisticsOrderUnit) && Objects.nonNull(kwtLogisticsOrderUnit.getEntId())){
            EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(kwtLogisticsOrderUnit.getEntId());
            truckInfoVo.setCarrier(Optional.ofNullable(entCacheResDto).map(EntCacheResDto::getFirmName).orElse(""));
        }
        return truckInfoVo;
    }

    private void saveRedisCache(String truckId, String wOrderNo, String truckNo, VehicleReturnData vehicleReturnData) {
        TruckDto truckDto = new TruckDto();
        truckDto.setWOrderNo(vehicleReturnData.getWOrderNo());
        truckDto.setTruckNo(truckNo);
        truckDto.setGpsStatus(String.valueOf(vehicleReturnData.getSpeed()));
        truckDto.setLongitude(vehicleReturnData.getLongitude());
        truckDto.setLatitude(vehicleReturnData.getLatitude());
        if (Objects.nonNull(vehicleReturnData.getTs())){
            LocalDateTime ts = vehicleReturnData.getTs().toLocalDateTime();
            Date date = Date.from(ts.toInstant(ZoneOffset.UTC));
            truckDto.setLocationTime(DateUtils.format(date, DateUtils.DATE_TIME_PATTERN));
        }
        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.findOneByWOrderNo(wOrderNo);
        truckDto.setLOrderNo(Objects.nonNull(subtask) ? String.valueOf(subtask.getLOrderId()):"");
        String taskAddress = getTaskAddress(subtask);
        truckDto.setTaskAddress(taskAddress);
        RedissonUtils.putString(CommonConstants.TRUCK_LOCATION + truckId +CommonConstants.UNDERSCORE+ wOrderNo, JSON.toJSONString(truckDto),10,TimeUnit.DAYS);
    }


    public String getTaskAddress(KwtWaybillOrderSubtask subtask) {
        String startPoint = "";
        String endPoint = "";
        if (Objects.nonNull(subtask)){
            List<KwtWaybillOrderAddress> kwtWaybillOrderAddresses = kwtWaybillOrderAddressRepository.queryByWOrderId(subtask.getWOrderId());
            if (CollectionUtils.isNotEmpty(kwtWaybillOrderAddresses)){
                for (KwtWaybillOrderAddress e : kwtWaybillOrderAddresses) {
                    if (Objects.equals(e.getAddressType(), AddressTypeEnum.SHIPMENT.getCode())) {
                        startPoint = e.getDetailAddress();
                    }
                    if (Objects.equals(e.getAddressType(), AddressTypeEnum.TAKE.getCode())) {
                        endPoint = e.getDetailAddress();
                    }
                }
            }
        }
        return startPoint+"-" + endPoint;
    }


    private TruckInfoVo getTruckInfoVoByZj(String truckNo, String wOrderNo,String truckId) {
        CollectZjxlResponse collectZjxlResponse = vehicleCollectService.transTimeManage(truckNo);
        TruckInfoVo instance = TruckInfoVo.getInstance();
        instance.setOrderNo(wOrderNo);
        instance.setTruckNo(truckNo);
        if (Objects.nonNull(collectZjxlResponse) && Objects.nonNull(collectZjxlResponse.getResult()) && Objects.nonNull(collectZjxlResponse.getResult().getFirstVcl())){
            instance.setGpsStatus(collectZjxlResponse.getResult().getFirstVcl().getSpd());
            instance.setLongitude(collectZjxlResponse.getResult().getFirstVcl().getLon());
            instance.setLatitude(collectZjxlResponse.getResult().getFirstVcl().getLat());
            instance.setLocationTime(collectZjxlResponse.getResult().getFirstVcl().getOfflineTime());
        }
        //查询关联订单号

        KwtWaybillOrder oneByTruckNo = kwtWaybillOrderRepository.findOneByTruckNo(truckNo,null);

        KwtWaybillOrderSubtask waybillOrderSubtask = kwtWaybillOrderSubtaskRepository.findOneByWOrderNo(oneByTruckNo.getWOrderNo());
        instance.setLogicOrderNo(Objects.nonNull(waybillOrderSubtask) && Objects.nonNull(waybillOrderSubtask.getLOrderId())
                ? String.valueOf(waybillOrderSubtask.getLOrderId()) : "");
        String taskAddress = getTaskAddress(waybillOrderSubtask);
        instance.setTaskAddress(taskAddress);
        return instance;
    }

    /**
     * 将数据中台的数据进行组织
     * @param truckId 车辆id
     * @param vehicleReturn 中台数据
     * @return 组织的数据
     */
    private TruckInfoVo buildTruckInfo(String truckId, VehicleReturnData vehicleReturn, String truckNo,KwtWaybillOrder order) {
        TruckInfoVo truckInfoVo = TruckInfoVo.getInstance();

        truckInfoVo.setTruckNo(truckNo);
        truckInfoVo.setGpsStatus(String.valueOf(vehicleReturn.getSpeed()));
        truckInfoVo.setLongitude(vehicleReturn.getLongitude());
        truckInfoVo.setLatitude(vehicleReturn.getLatitude());
        truckInfoVo.setLocationTime(Objects.isNull(vehicleReturn.getTs())? "" : DateUtils.format(vehicleReturn.getTs().toLocalDateTime(),DateUtils.DATE_TIME_PATTERN));
        if (Objects.nonNull(order)){
            truckInfoVo.setTruckNo(order.getTruckNo());
            truckInfoVo.setOrderNo(order.getWOrderNo());
            truckInfoVo.setDriveId(String.valueOf(order.getDriverId()));
            truckInfoVo.setDriveName(order.getDriverName());
            truckInfoVo.setDrivePhone(order.getDriverPhone());
            truckInfoVo.setTruckId(truckId);
            truckInfoVo.setTaskStatus(String.valueOf(order.getStatus()));
        }

        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.findOneByWOrderNo(Optional.ofNullable(order)
                .map(KwtWaybillOrder::getWOrderNo).
                orElse( null));
        truckInfoVo.setLogicOrderNo(Objects.isNull(subtask) ? "" : String.valueOf(subtask.getLOrderId()));
        if (Objects.isNull(subtask)){
            return truckInfoVo;
        }
        //根据物流订单号查询承运单位 2.代表承运企业
        KwtLogisticsOrderUnit kwtLogisticsOrderUnit = kwtLogisticsOrderUnitRepository.queryByLOrderIdAndUnitType(subtask.getLOrderId(), 2);
        if (Objects.nonNull(kwtLogisticsOrderUnit) && Objects.nonNull(kwtLogisticsOrderUnit.getEntId())){
            EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(kwtLogisticsOrderUnit.getEntId());
            truckInfoVo.setCarrier(Optional.ofNullable(entCacheResDto).map(EntCacheResDto::getFirmName).orElse(""));
        }

        List<KwtWaybillOrderAddress> kwtWaybillOrderAddresses = kwtWaybillOrderAddressRepository.queryByWOrderId(subtask.getWOrderId());
        if (CollectionUtils.isEmpty(kwtWaybillOrderAddresses)){
            return truckInfoVo;
        }
        String startPoint = "";
        String endPoint = "";
        for (KwtWaybillOrderAddress kwtWaybillOrderAddress : kwtWaybillOrderAddresses) {
            if (Objects.equals(kwtWaybillOrderAddress.getAddressType(), AddressTypeEnum.SHIPMENT.getCode())) {
                startPoint = kwtWaybillOrderAddress.getDetailAddress();
            }
            if (Objects.equals(kwtWaybillOrderAddress.getAddressType(), AddressTypeEnum.TAKE.getCode())) {
               endPoint = kwtWaybillOrderAddress.getDetailAddress();
            }
        }
        truckInfoVo.setTaskAddress(startPoint+"-"+endPoint);
        //查询物流商品
        KwtLogisticsOrderGoods kwtLogisticsOrderGoods = kwtLogisticsOrderGoodsRepository.queryByLogOrderId(subtask.getLOrderId());
        Long goodsId = Optional.ofNullable(kwtLogisticsOrderGoods)
                .map(KwtLogisticsOrderGoods::getGoodsId)
                .orElse(null);
        //查询商品
        KwpGoods goodsById = goodsInfoService.getGoodsById(goodsId);
        //查询字典
        Map<String, Map<String, String>> dictByTypeMap = remoteSystemService.queryDictByType(Arrays.asList(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.GOODS_SPEC.getType()));
        truckInfoVo.setGoodsName(goodsById.getName() + "/" + dictByTypeMap.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType()).get(goodsById.getGoodsType()) + "/" + dictByTypeMap.get(DictTypeEnum.GOODS_SPEC.getType()).get(goodsById.getSpec()));
        Long truck = com.sckw.core.utils.StringUtils.isNotBlank(truckId) ? Long.parseLong(truckId) : null;
        Optional.ofNullable(fleetService.findTruck(truck))
                .ifPresent(f->truckInfoVo.setAxleNum(f.getCarAxis()));
        return truckInfoVo;
    }

    /**
     * 查询当前任务的轨迹
     * @param req 请求参数，包含车辆编号和订单号等信息
     * @return 当前任务轨迹信息，包括轨迹点列表和地址点列表
     */
    public CurrentTaskTraceReqVo queryCurrentTaskTrace(CurrentTaskTraceReq req) {
        log.info("查询当前任务轨迹参数：{}", req);

        // 获取当前登录用户的企业ID
        Long entId = LoginUserHolder.getEntId();
        String wOrderNo = StringUtils.EMPTY ;
        // 如果请求中包含订单号，则直接使用；否则根据车牌号查询对应订单号
        if (StringUtils.isNotBlank(req.getOrderNo())){
            wOrderNo  = req.getOrderNo();
        }else {
            //根据企业查询物流订单
            List<KwtLogisticsOrderUnit> kwtLogisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByEntId(entId);
            if (CollUtil.isEmpty(kwtLogisticsOrderUnits)) {
                log.info("该企业未查询到物流订单数据，企业id:{}", entId);
                return new CurrentTaskTraceReqVo();
            }
            //获取物流订单号
            Set<Long> logOrderIds = kwtLogisticsOrderUnits.stream()
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .collect(Collectors.toSet());
            if (CollUtil.isEmpty(logOrderIds)) {
                log.info("该企业下物流订单数据，企业id:{}", entId);
                return new CurrentTaskTraceReqVo();
            }
            //查询子运单
            List<KwtWaybillOrderSubtask> kwtWaybillOrderSubtasks = waybillOrderSubtaskDao.selectList(Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
                    .in(KwtWaybillOrderSubtask::getLOrderId, logOrderIds)
                    .eq(BaseModel::getDelFlag, 0));
            if(org.apache.commons.collections4.CollectionUtils.isEmpty(kwtWaybillOrderSubtasks)){
                log.info("该企业下子运单的订单数据不存在，企业id:{}", entId);
                return new CurrentTaskTraceReqVo();
            }
            Set<Long> wayOrderIds = kwtWaybillOrderSubtasks.stream()
                    .map(KwtWaybillOrderSubtask::getWOrderId)
                    .collect(Collectors.toSet());
            KwtWaybillOrder waybillOrder = kwtWaybillOrderRepository.findOneByTruckNo(req.getTruckNo(),wayOrderIds);
            wOrderNo = Optional.ofNullable(waybillOrder).map(KwtWaybillOrder::getWOrderNo).orElse("");
        }
        
        // 查询数据中台获取轨迹数据
        List<VehicleReturnData> vehicleReturnDataList = getVehicleReturnDataList(wOrderNo);

        CurrentTaskTraceReqVo currentTaskTraceReqVo = new CurrentTaskTraceReqVo();
        
        // 如果轨迹数据不为空，则处理轨迹点信息
        if (CollectionUtils.isNotEmpty(vehicleReturnDataList)){
            // 将VehicleReturnData转换为CurrentTaskTrace，并按时间排序
            List<CurrentTaskTraceReqVo.CurrentTaskTrace> currentTaskTraceList = vehicleReturnDataList.stream()
                    .map(kwfTruckTraceService::getCurrentTaskTrace)
                    .filter(x->StringUtils.isNotBlank(x.getLocationTime()))
                    .sorted(Comparator.comparing(CurrentTaskTraceReqVo.CurrentTaskTrace::getLocationTime))
                    .collect(Collectors.toList());

            // 设置订单号
            currentTaskTraceReqVo.setOrderNo(vehicleReturnDataList.get(0).getWOrderNo());

            // 计算相邻轨迹点之间的时间间隔（分钟）
            for (int i = 1; i < currentTaskTraceList.size(); i++) {
                CurrentTaskTraceReqVo.CurrentTaskTrace current = currentTaskTraceList.get(i);
                CurrentTaskTraceReqVo.CurrentTaskTrace previous = currentTaskTraceList.get(i - 1);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime currentTime = LocalDateTime.parse(current.getLocationTime(), formatter);
                LocalDateTime previousTime = LocalDateTime.parse(previous.getLocationTime(), formatter);
                Duration duration = Duration.between(previousTime, currentTime);
                current.setDuration(String.valueOf(duration.toMinutes()));
            }
            
            // 计算总时长（第一个点到最后一个点的时间差）
            CurrentTaskTraceReqVo.CurrentTaskTrace first = currentTaskTraceList.get(0);
            CurrentTaskTraceReqVo.CurrentTaskTrace last = currentTaskTraceList.get(currentTaskTraceList.size() - 1);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime firstTime = LocalDateTime.parse(first.getLocationTime(),formatter);
            LocalDateTime lastTime = LocalDateTime.parse(last.getLocationTime(),formatter);

            Duration totalDuration = Duration.between(firstTime, lastTime);
            long durationInMinutes = totalDuration.toMinutes();
            currentTaskTraceReqVo.setTotalDuration(String.valueOf(durationInMinutes));
            currentTaskTraceReqVo.setCurrentTaskTraceList(currentTaskTraceList);
        }

        // 构造点位假数据（用于演示或测试）
        List<CurrentTaskTraceReqVo.CurrentAddress> addressList = getCurrentAddresses();
        // 将地址列表设置到 CurrentTaskTraceReqVo 对象中
        currentTaskTraceReqVo.setCurrentAddressList(addressList);
        
        // 计算地址点的总时长
        int sum = addressList.stream()
                .filter(a -> StringUtils.isNotBlank(a.getDuration()))
                .mapToInt(x -> Integer.parseInt(x.getDuration()))
                .sum();
        currentTaskTraceReqVo.setTotalDuration(String.valueOf(sum));
        return currentTaskTraceReqVo;
    }


    private static List<CurrentTaskTraceReqVo.CurrentAddress> getCurrentAddresses() {
        // 创建四条 CurrentAddress 数据
        List<CurrentTaskTraceReqVo.CurrentAddress> addressList = new ArrayList<>();

        // 第一条数据
        CurrentTaskTraceReqVo.CurrentAddress address1 = new CurrentTaskTraceReqVo.CurrentAddress();
        address1.setPoint("金顶集团");
        address1.setDuration("0");
        addressList.add(address1);

        // 第二条数据
        CurrentTaskTraceReqVo.CurrentAddress address2 = new CurrentTaskTraceReqVo.CurrentAddress();
        address2.setPoint("乐山高速路入口");
        address2.setDuration("30");
        addressList.add(address2);

        // 第三条数据
        CurrentTaskTraceReqVo.CurrentAddress address3 = new CurrentTaskTraceReqVo.CurrentAddress();
        address3.setPoint("乐山高速路出口");
        address3.setDuration("50");
        addressList.add(address3);

        // 第四条数据
        CurrentTaskTraceReqVo.CurrentAddress address4 = new CurrentTaskTraceReqVo.CurrentAddress();
        address4.setPoint("乐山大佛加工厂");
        address4.setDuration("60");
        addressList.add(address4);
        addressList = addressList.stream()
                .sorted(Comparator.comparing(CurrentTaskTraceReqVo.CurrentAddress::getDuration))
                .collect(Collectors.toList());
        return addressList;
    }

    /**
     * 查询数据中台获取轨迹
     * @param wOrderNo 运单号
     * @return 轨迹数据
     */
    private List<VehicleReturnData> getVehicleReturnDataList(String wOrderNo) {
        VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
        vehicleDataDTO.setWOrderNo(wOrderNo);
        vehicleDataDTO.setOrderNo(wOrderNo);
        
        try {
            // 使用 Feign 调用查询车辆轨迹列表
            log.info("查询任务轨迹列表请求参数: {}", JSON.toJSONString(vehicleDataDTO));
            BaseIotResult<List<VehicleReturnData>> result = vehicleTraceClient.queryVehicleDataList(vehicleDataDTO);
            log.info("查询任务轨迹列表返回数据: {}", JSON.toJSONString(result));
            if (result == null || !StringUtils.equals(result.getCode(), "0") || result.getData() == null) {
                log.warn("查询任务轨迹返回空数据, 运单号: {}", wOrderNo);
                return List.of();
            }
            return result.getData();
        } catch (Exception e) {
            log.error("查询任务轨迹异常, 运单号: {}", wOrderNo, e);
            throw new BusinessException("查询任务轨迹异常");
        }
    }

    public VehicleReturnData getVehicleReturnData(String truckId) {
        VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
        vehicleDataDTO.setCarNo(truckId);

        try {
            // 使用 Feign 调用查询实时位置
            BaseIotResult<VehicleReturnData> result = vehicleTraceClient.queryRealTimeLocation(vehicleDataDTO);
            log.info("查询实时轨迹返回数据: {}", JSON.toJSONString( result));
            if (result == null || !Objects.equals(result.getCode(), "0") || result.getData() == null) {
                log.warn("查询实时轨迹返回空数据, 车牌号: {}", truckId);
                return null;
            }

            return result.getData();
        } catch (Exception e) {
            log.error("查询任务轨迹异常, 车牌号: {}", truckId, e);
            return null;
        }
    }

    private static CurrentTaskTraceReqVo.CurrentTaskTrace getCurrentTaskTrace(VehicleReturnData e) {
        CurrentTaskTraceReqVo.CurrentTaskTrace currentTaskTrace = new CurrentTaskTraceReqVo.CurrentTaskTrace();
        currentTaskTrace.setLongitude(e.getLongitude());
        currentTaskTrace.setLatitude(e.getLatitude());
        currentTaskTrace.setLocationTime(Objects.isNull(e.getTs()) ? "" : DateUtils.format(e.getTs().toLocalDateTime(), DateUtils.DATE_TIME_PATTERN));
        currentTaskTrace.setStatus(e.getStatus());
        // 处理数据库状态值的兼容逻辑
        int status = 0;
        try {
            status = Integer.parseInt(e.getStatus());
        }catch (Exception ex){
            log.info("状态码转换异常",ex);
        }

        currentTaskTrace.setStatusDesc(VehicleExceptionTypeEnum.getName(status));
        return currentTaskTrace;
    }

    /**
     * 查询车辆轨迹
     * @param req 轨迹参数
     * @return 轨迹数据
     */
    public CurrentTaskTraceReqVo queryCurrentTruckTrace(CurrentTaskTraceReq req) {
        log.info("查询车辆轨迹参数：{}", req);
        if (StringUtils.isBlank(req.getTruckNo())){
            throw  new BusinessException("车牌号不能为空");
        }
        //cxf todo 查询车辆td数据库

        return new CurrentTaskTraceReqVo();
    }

    /**
     * 上报车辆轨迹
     * @param req 请求参数
     * @return 响应参数
     */
    public Void vehiclesTrajectory( VehiclesTrajectoryReq req) {
        //通过手机号查询司机以及车辆信息
        //req.setTs(DateUtils.format(new Date(),DateUtils.DATE_TIME_PATTERN));
        RDriverVo rDriverVo = fleetService.findDriverByPhone(req.getMobile());
        if (Objects.isNull(rDriverVo)){
            throw new BusinessException("司机信息不存在");
        }
        initReq(req);
        //查询认为中的运单信息
        KwtWaybillOrder waybillOrder = kwtWaybillOrderRepository.findOneByDriverId(rDriverVo.getId());
        //获取车队信息
        RFleetDriverVo fleetByDriveId = fleetService.findFleetByDriveId(rDriverVo.getId());
        req.setLOrderNo(Optional.ofNullable(waybillOrder)
                .map(KwtWaybillOrder::getWOrderNo).orElse(""));
        req.setWOrderNo(Optional.ofNullable(waybillOrder)
                .map(KwtWaybillOrder::getWOrderNo).orElse(""));
        VehiclesTrajectoryReq.VehicleDataVO vehicleDataVO = new VehiclesTrajectoryReq.VehicleDataVO();
        //车牌id     cxf todo 车牌号写死
        Long truckId = Optional.ofNullable(waybillOrder)
                .map(KwtWaybillOrder::getTruckId)
                .orElse(195160604170784768L);

        req.setTruckNo(String.valueOf(truckId));
        vehicleDataVO.setCarNo(String.valueOf(truckId));

        vehicleDataVO.setFleetId(String.valueOf(Optional.ofNullable(fleetByDriveId)
                .map(RFleetDriverVo::getFleetId)
                .orElse(null)));
        req.setVehicleDataVO(vehicleDataVO);
        req.setStatus("1");
        
        try {
            // 使用 Feign 调用上报车辆轨迹
            BaseIotResult<Void> result = vehicleTraceClient.saveVehicleData(req);
            
            if (result == null || result.getCode() != "0") {
                log.error("app上报车辆轨迹失败, 响应: {}", result);
                throw new BusinessException("app上报车辆轨迹异常");
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("app上报车辆轨迹异常", e);
            throw new BusinessException("app上报车辆轨迹异常");
        }
        String key = CommonConstants.TRUCK_LOCATION + truckId+CommonConstants.UNDERSCORE;
        String xwOrderNo = "";
        if (Objects.nonNull(waybillOrder)){
            xwOrderNo = waybillOrder.getWOrderNo();
            key = CommonConstants.TRUCK_LOCATION + truckId+CommonConstants.UNDERSCORE+xwOrderNo;
        }
        //先删除缓存
        RedissonUtils.delete(key);
        //组织缓存数据
        TruckDto truckDto = getTruckDto(req,xwOrderNo);
        //放入缓存  存十天
        RedissonUtils.putString(key,JSON.toJSONString(truckDto),10, TimeUnit.DAYS);
        return null;
    }

    private void initReq(VehiclesTrajectoryReq req) {
        req.setGpsStatus(req.getStatus());
        req.setDirection(30.0f);
        req.setFuelLevel(30.0f);
        req.setMileage("1.0");
        req.setEngineTemp(25.0f);
        req.setBatteryVoltage(12.0f);
        req.setStatus("1");
        req.setAlarmCode("123");
    }

    /**
     * 组织返回数据
     * @param req 请求参数
     * @return 缓存数据
     */
    private TruckDto getTruckDto(VehiclesTrajectoryReq req,String wOrderNo) {
        TruckDto truckDto = new TruckDto();
        truckDto.setWOrderNo(wOrderNo);
        truckDto.setTruckNo(req.getTruckNo());
        truckDto.setGpsStatus(String.valueOf(req.getSpeed()));
        truckDto.setLongitude(req.getLongitude());
        truckDto.setLatitude(req.getLatitude());
        truckDto.setLocationTime(DateUtils.format(LocalDateTime.now(), DateUtils.DATE_TIME_PATTERN));
        truckDto.setLOrderNo(req.getLOrderNo());
        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.findOneByWOrderNo(wOrderNo);
        String taskAddress = getTaskAddress(subtask);
        truckDto.setTaskAddress(taskAddress);
        return truckDto;
    }

    /**
     * 查询车辆下拉列表（支持多选和输入匹配）
     * @param req 查询请求
     * @return 车辆下拉列表
     */
public List<TruckSelectVo> getTruckSelectList(TruckSelectReq req) {
    // 参数校验
    if (req == null) {
        log.warn("查询车辆下拉列表参数为空");
        return Collections.emptyList();
    }

    log.info("查询车辆下拉列表参数：{}", JSON.toJSONString(req));

    // 获取当前企业ID
    Long entId = LoginUserHolder.getEntId();

    // 获取物流订单ID集合
    Set<Long> logOrderIds = getLogisticsOrderIds(entId);
    if (CollUtil.isEmpty(logOrderIds)) {
        return Collections.emptyList();
    }

    // 获取运单ID集合
    Set<Long> wayOrderIds = getWayOrderIds(logOrderIds);
    if (CollectionUtils.isEmpty(wayOrderIds)) {
        return Collections.emptyList();
    }

    // 查询车辆运单数据
    List<KwtWaybillOrder> waybillOrders = queryWaybillOrders(req, wayOrderIds);
    if (CollectionUtils.isEmpty(waybillOrders)) {
        return Collections.emptyList();
    }

    // 获取车辆位置状态映射
    Map<String, Integer> truckLocationStatusMap = getTruckLocationStatusMap(
            getTruckIdTruckNoMap(waybillOrders));

    // 转换为 VO 对象并根据状态筛选
    Integer locationStatusFilter = req.getLocationStatus();

    return waybillOrders.stream()
            .map(order -> buildTruckSelectVo(order, truckLocationStatusMap))
            // 根据请求参数筛选定位状态
            .filter(vo -> locationStatusFilter == null || vo.getLocationStatus().equals(locationStatusFilter))
            // 按定位状态降序排序
            .sorted(Comparator.comparing(TruckSelectVo::getLocationStatus).reversed())
            .collect(Collectors.toList());
}

/**
 * 获取物流订单ID集合
 */
private Set<Long> getLogisticsOrderIds(Long entId) {
    // 根据企业查询物流订单
    List<KwtLogisticsOrderUnit> logisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByEntId(entId);
    if (CollUtil.isEmpty(logisticsOrderUnits)) {
        log.info("该企业未查询到物流订单数据，企业id:{}", entId);
        return Collections.emptySet();
    }

    // 获取物流订单号
    return logisticsOrderUnits.stream()
            .map(KwtLogisticsOrderUnit::getLOrderId)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
}

/**
 * 获取运单ID集合
 */
private Set<Long> getWayOrderIds(Set<Long> logOrderIds) {
    // 查询子运单
    List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskDao.selectList(
            Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
                    .in(KwtWaybillOrderSubtask::getLOrderId, logOrderIds)
                    .eq(BaseModel::getDelFlag, 0));

    if (CollectionUtils.isEmpty(waybillOrderSubtasks)) {
        log.info("该企业下子运单的订单数据不存在，企业id:{}", LoginUserHolder.getEntId());
        return Collections.emptySet();
    }

    return waybillOrderSubtasks.stream()
            .map(KwtWaybillOrderSubtask::getWOrderId)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
}

/**
 * 查询车辆运单数据
 */
private List<KwtWaybillOrder> queryWaybillOrders(TruckSelectReq req, Set<Long> wayOrderIds) {
    return kwtWaybillOrderRepository.selectTruckListForSelect(
            req.getTruckNo(), wayOrderIds, req.getWaybillOrderNo());
}

/**
 * 获取车辆ID和车牌号映射
 */
private Map<Long, String> getTruckIdTruckNoMap(List<KwtWaybillOrder> waybillOrders) {
    return waybillOrders.stream()
            .filter(order -> Objects.nonNull(order.getTruckId()))
            .collect(Collectors.toMap(
                    KwtWaybillOrder::getTruckId,
                    KwtWaybillOrder::getTruckNo,
                    (key1, key2) -> key1));
}

/**
 * 构建车辆选择VO
 */
private TruckSelectVo buildTruckSelectVo(KwtWaybillOrder order, Map<String, Integer> truckLocationStatusMap) {
    TruckSelectVo vo = new TruckSelectVo();
    BeanUtils.copyProperties(order, vo);

    String truckNo = order.getTruckNo();
    if (StringUtils.isNotBlank(truckNo) && truckLocationStatusMap != null) {
        vo.setLocationStatus(truckLocationStatusMap.getOrDefault(truckNo, 0));
    } else {
        vo.setLocationStatus(0);
    }

    return vo;
}

/**
 * 获取车辆位置状态映射
 */
private Map<String, Integer> getTruckLocationStatusMap(Map<Long, String> truckIdTruckNoMap) {
    if (MapUtils.isEmpty(truckIdTruckNoMap)) {
        return Collections.emptyMap();
    }

    // 批量查询实时位置状态（30分钟内有数据为在线）
    return getStringIntegerMap(truckIdTruckNoMap);
}


    @NotNull
    private Map<String, Integer> getStringIntegerMap(Map<Long, String> truckIdTruckNoMap) {
        Map<String, Integer> truckLocationStatusMap = new HashMap<>();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime thirtyMinutesAgo = now.minusMinutes(30);
        if (MapUtils.isEmpty(truckIdTruckNoMap)){
            return truckLocationStatusMap;
        }
        truckIdTruckNoMap.forEach((truckId, truckNo) -> {
            try {
                VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                vehicleDataDTO.setCarNo(Objects.isNull(truckId) ? "0" : String.valueOf(truckId));
                BaseIotResult<VehicleReturnData> result = vehicleTraceClient.queryRealTimeLocation(vehicleDataDTO);

                if (result == null || !Objects.equals(result.getCode(), "0") || result.getData() == null) {
                    // 无定位数据，设置为离线
                    truckLocationStatusMap.put(truckNo, 0);
                    return;
                }

                VehicleReturnData vehicleData = result.getData();

                // 判断定位时间是否在30分钟内
                if (vehicleData.getTs() == null) {
                    // 无GPS时间，设置为离线
                    truckLocationStatusMap.put(truckNo, 0);
                    return;
                }

                // 30分钟内为在线
                if (vehicleData.getTs().toLocalDateTime().isAfter(thirtyMinutesAgo)) {
                    truckLocationStatusMap.put(truckNo, 1);
                } else {
                    truckLocationStatusMap.put(truckNo, 0);
                }

            } catch (Exception e) {
                log.warn("查询车辆实时位置异常, 车牌号: {}", truckNo, e);
                truckLocationStatusMap.put(truckNo, 0);
            }
        });
        return truckLocationStatusMap;
    }

    @NotNull
    private static TruckSelectVo getTruckSelectVo(KwtWaybillOrder order, Map<String, Integer> truckLocationStatusMap) {
        TruckSelectVo vo = new TruckSelectVo();
        vo.setTruckId(order.getTruckId());
        vo.setTruckNo(order.getTruckNo());
        vo.setDriverName(order.getDriverName());
        vo.setDriverPhone(order.getDriverPhone());
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(CarWaybillV1Enum.geDesc(order.getStatus()));

        // 设置定位状态
        Integer locationStatus = truckLocationStatusMap.getOrDefault(order.getTruckNo(), 0);
        vo.setLocationStatus(locationStatus);
        vo.setLocationStatusDesc(locationStatus == 1 ? "在线" : "离线");

        return vo;
    }

    /**
     * 分页查询地图车辆列表
     * @param req 查询请求
     * @return 分页结果
     */
    /**
     * 分页查询地图车辆列表
     * @param req 查询请求参数，包括日期范围、状态、车牌号、承运单位、托运单位等筛选条件
     * @return 分页结果，包含车辆在地图上的相关信息
     */
    public PageDataResult<MapVehicleVo> queryMapVehicleList(MapVehicleQueryReq req) {
        // 打印查询参数日志
        log.info("分页查询地图车辆列表参数：{}", req);

        // 处理日期参数，默认为当天
        Date startDate = getStartDate(req.getStartDate());
        Date endDate = getEndDate(req.getEndDate());

        // 构建查询状态列表，如果未指定状态则查询任务中的订单
        List<Integer> taskingStatus = buildTaskingStatus(req.getStatus());

        // 前置条件：根据承运单位和托运单位筛选出符合条件的运单ID
        Set<Long> wayOrderIds = getWayOrderIds(req, getAllEnt());
        // 如果没有符合条件的运单ID，直接返回空结果
        if (shouldReturnEmptyResult(req, wayOrderIds)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        // 使用 MyBatis-Plus 分页查询（如果有前置筛选条件，则添加运单ID的IN条件）
        // 根据日期范围、状态、运单ID、车牌号等条件查询运单信息
        IPage<KwtWaybillOrder> page = kwtWaybillOrderRepository.queryMapVehicleListPage(startDate, endDate, taskingStatus, wayOrderIds,req.getTrackNo(), req.getPageNum(),req.getPageSize() );
        
        List<KwtWaybillOrder> waybillOrders = page.getRecords();
        if (CollectionUtils.isEmpty(waybillOrders)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        // 提取运单ID列表，用于后续批量查询
        List<Long> wOrderIds = extractWOrderIds(waybillOrders);
        // 提取车辆ID列表，用于查询车辆详细信息
        List<Long> truckIds = extractTruckIds(waybillOrders);

        // 批量查询相关数据，提高查询效率
        Map<Long, RTruckVo> truckIdMap = batchQueryTruckInfo(truckIds);
        // 批量查询子运单信息
        Map<Long, KwtWaybillOrderSubtask> wOrderIdSubtaskMap = batchQuerySubtasks(wOrderIds);
        // 从子运单信息中提取物流订单ID
        Set<Long> lOrderIds = extractLOrderIds(wOrderIdSubtaskMap);

        // 批量查询物流订单相关数据（单位、货物、地址、订单信息）
        LogisticsOrderData logisticsOrderData = batchQueryLogisticsOrderData(lOrderIds);

        // 批量查询定位和异常信息
        Map<String, VehicleLocationInfo> locationInfoMap = batchQueryLocationInfo(waybillOrders);
        Map<String, Integer> exceptionCountMap = batchQueryExceptionCount(waybillOrders);

        // 获取字典数据，用于车辆能源类型转换
        Map<String, SysDictResDto> energyTypeMap = getEnergyTypeMap();

        // 根据定位状态筛选（在线/离线），如果未指定定位状态则不过滤
        List<KwtWaybillOrder> filteredOrders = filterByLocationStatus(waybillOrders, locationInfoMap, req.getLocationStatus());

        // 将查询结果转换为前端需要的VO对象
        List<MapVehicleVo> result = convertToMapVehicleVos(
                filteredOrders, wOrderIdSubtaskMap, logisticsOrderData,
                locationInfoMap, exceptionCountMap, truckIdMap, energyTypeMap);
        // 根据过滤后的结果创建新的分页对象，确保总数准确
        Page<MapVehicleVo> filteredPage = new Page<>();
        filteredPage.setCurrent(page.getCurrent());
        filteredPage.setSize(page.getSize());
        filteredPage.setTotal(filteredOrders.size()); // 使用过滤后的实际数量
        filteredPage.setRecords(result);

        // 返回分页结果（使用数据库分页的总数）
        return PageDataResult.of(filteredPage, result);
    }

    /**
     * 构建查询状态列表
     */

    /**
     * 构建查询状态列表
     * 如果传入了具体状态，则只查询该状态；否则查询任务中（进行中）的订单状态列表
     * 
     * @param status 传入的查询状态，如果为null则使用默认的任务中状态列表
     * @return 状态码列表，用于数据库查询条件
     */
    private List<Integer> buildTaskingStatus(Integer status) {
        if (Objects.nonNull(status)) {
            // 如果指定了具体状态，只返回该状态的列表
            return Collections.singletonList(status);
        }
        // 默认返回任务进行中的各种状态
        return Arrays.asList(
                CarWaybillV1Enum.PENDING_VEHICLE.getCode(),  // 待提货
                CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),   // 拒绝运输
                CarWaybillV1Enum.EXIT_COMPLETED.getCode(),   // 出口完成
                CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode(),
                CarWaybillV1Enum.WAIT_LEAVE.getCode(),
                CarWaybillV1Enum.UNLOADING.getCode(),
                CarWaybillV1Enum.WAIT_RELEASE.getCode(),
                CarWaybillV1Enum.REPLENISHING.getCode(),
                CarWaybillV1Enum.REPLENISH_FINISH.getCode(),
                CarWaybillV1Enum.RELEASED_NOT_EXITED.getCode(),
                CarWaybillV1Enum.WAIT_LOADING.getCode()      // 等待装货
        );
    }

    /**
     * 判断是否应返回空结果
     */
    private boolean shouldReturnEmptyResult(MapVehicleQueryReq req, Set<Long> wayOrderIds) {
        return CollectionUtils.isEmpty(wayOrderIds) &&
                (StringUtils.isNotBlank(req.getLogisticOrderNo()) ||
                        Objects.nonNull(req.getCarrierEntId()) ||
                        Objects.nonNull(req.getConsignEntId()) ||
                        Objects.nonNull(LoginUserHolder.getEntId()));
    }

    /**
     * 提取运单ID列表
     */
    private List<Long> extractWOrderIds(List<KwtWaybillOrder> waybillOrders) {
        return waybillOrders.stream()
                .map(KwtWaybillOrder::getId)
                .collect(Collectors.toList());
    }

    /**
     * 提取车辆ID列表
     */
    private List<Long> extractTruckIds(List<KwtWaybillOrder> waybillOrders) {
        return waybillOrders.stream()
                .map(KwtWaybillOrder::getTruckId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 批量查询车辆信息
     */
    private Map<Long, RTruckVo> batchQueryTruckInfo(List<Long> truckIds) {
        if (CollectionUtils.isEmpty(truckIds)) {
            return Collections.emptyMap();
        }

        List<RTruckVo> truckVos = fleetService.findTruckByTruckIds(truckIds);
        if (CollectionUtils.isEmpty(truckVos)) {
            return Collections.emptyMap();
        }

        return truckVos.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(RTruckVo::getId, Function.identity(), (k1, k2) -> k1));
    }

    /**
     * 批量查询子运单信息
     */
    private Map<Long, KwtWaybillOrderSubtask> batchQuerySubtasks(List<Long> wOrderIds) {
        if (CollectionUtils.isEmpty(wOrderIds)) {
            return Collections.emptyMap();
        }

        List<KwtWaybillOrderSubtask> subtasks = kwtWaybillOrderSubtaskRepository.queryByWOrderIds(wOrderIds);
        if (CollectionUtils.isEmpty(subtasks)) {
            return Collections.emptyMap();
        }

        return subtasks.stream()
                .filter(subtask -> subtask.getWOrderId() != null)
                .collect(Collectors.toMap(KwtWaybillOrderSubtask::getWOrderId, Function.identity(), (k1, k2) -> k1));
    }

    /**
     * 提取物流订单ID集合
     */
    private Set<Long> extractLOrderIds(Map<Long, KwtWaybillOrderSubtask> wOrderIdSubtaskMap) {
        return wOrderIdSubtaskMap.values().stream()
                .map(KwtWaybillOrderSubtask::getLOrderId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
    }

    /**
     * 批量查询物流订单相关数据
     */
    private LogisticsOrderData batchQueryLogisticsOrderData(Set<Long> lOrderIds) {
        LogisticsOrderData data = new LogisticsOrderData();

        if (CollectionUtils.isEmpty(lOrderIds)) {
            return data;
        }

        List<Long> lOrderIdList = new ArrayList<>(lOrderIds);

        // 查询物流订单单位
        data.setUnits(kwtLogisticsOrderUnitRepository.queryByLOrderIds(lOrderIdList));

        // 查询商品信息
        data.setGoods(kwtLogisticsOrderGoodsRepository.queryByLOrderIds(lOrderIdList));

        // 查询物流地址
        data.setAddresses(kwtLogisticsOrderAddressRepository.queryByLogOrderIds(lOrderIdList));

        // 查询物流订单
        List<KwtLogisticsOrder> logisticsOrders = kwtLogisticsOrderRepository.queryByLogisticsOrderIds(lOrderIdList);
        data.setOrders(Optional.ofNullable(logisticsOrders)
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(KwtLogisticsOrder::getId, Function.identity(), (k1, k2) -> k1)));

        return data;
    }

    /**
     * 批量查询定位信息
     */
    private Map<String, VehicleLocationInfo> batchQueryLocationInfo(List<KwtWaybillOrder> waybillOrders) {
        Map<Long, String> truckIdAndTruckNoMap = waybillOrders.stream()
                .filter(order -> Objects.nonNull(order.getTruckId()))
                .collect(Collectors.toMap(KwtWaybillOrder::getTruckId, KwtWaybillOrder::getTruckNo, (k1, k2) -> k1));

        return queryVehicleLocationBatch(truckIdAndTruckNoMap);
    }

    /**
     * 批量查询异常数量
     */
    private Map<String, Integer> batchQueryExceptionCount(List<KwtWaybillOrder> waybillOrders) {
        List<String> wOrderNos = waybillOrders.stream()
                .map(KwtWaybillOrder::getWOrderNo)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        return countExceptionsByTraceData(wOrderNos);
    }

    /**
     * 获取能源类型字典
     */
    private Map<String, SysDictResDto> getEnergyTypeMap() {
        List<SysDictResDto> sysDictResDtos = remoteSystemService.queryDictByType(DictTypeEnum.ENERGY_TYPE.getType());
        if (CollectionUtils.isEmpty(sysDictResDtos)) {
            return Collections.emptyMap();
        }

        return sysDictResDtos.stream()
                .collect(Collectors.toMap(SysDictResDto::getValue, Function.identity(), (k1, k2) -> k1));
    }

    /**
     * 根据定位状态筛选
     */

    /**
     * 根据定位状态筛选运单订单
     * 
     * @param waybillOrders 运单订单列表
     * @param locationInfoMap 车辆位置信息映射，key为车牌号，value为位置信息
     * @param locationStatus 定位状态筛选条件（1-在线，0-离线），如果为null则不过滤
     * @return 筛选后的运单订单列表
     */
    private List<KwtWaybillOrder> filterByLocationStatus(
            List<KwtWaybillOrder> waybillOrders,
            Map<String, VehicleLocationInfo> locationInfoMap,
            Integer locationStatus) {

        // 如果没有定位状态筛选条件，直接返回原列表
        if (locationStatus == null) {
            return waybillOrders;
        }

        // 根据定位状态筛选运单订单
        return waybillOrders.stream()
                .filter(order -> {
                    // 获取车辆的位置信息
                    VehicleLocationInfo locationInfo = locationInfoMap.get(order.getTruckNo());
                    // 筛选条件：位置信息存在且定位状态与筛选条件匹配
                    return locationInfo != null && locationStatus.equals(locationInfo.getLocationStatus());
                })
                .collect(Collectors.toList());
    }

    /**
     * 转换为MapVehicleVo列表
 * 该方法将过滤后的运单订单列表转换为MapVehicleVo对象列表
 *
 * @param filteredOrders 过滤后的运单订单列表
 * @param wOrderIdSubtaskMap 运单ID与子任务的映射关系
 * @param logisticsOrderData 物流订单数据对象
 * @param locationInfoMap 位置信息映射
 * @param exceptionCountMap 异常计数映射
 * @param truckIdMap 车辆ID映射
 * @param energyTypeMap 能源类型映射
 * @return 返回转换后的MapVehicleVo列表
     */

    private List<MapVehicleVo> convertToMapVehicleVos(
            List<KwtWaybillOrder> filteredOrders,
            Map<Long, KwtWaybillOrderSubtask> wOrderIdSubtaskMap,
            LogisticsOrderData logisticsOrderData,
            Map<String, VehicleLocationInfo> locationInfoMap,
            Map<String, Integer> exceptionCountMap,
            Map<Long, RTruckVo> truckIdMap,
            Map<String, SysDictResDto> energyTypeMap) {

        // 构建物流订单相关映射
        // 构建单位映射，用于快速查找物流订单中的单位信息
        Map<String, KwtLogisticsOrderUnit> unitMap = buildUnitMap(logisticsOrderData.getUnits());
        // 构建货物映射，用于快速查找物流订单中的货物信息
        Map<Long, KwtLogisticsOrderGoods> goodsMap = buildGoodsMap(logisticsOrderData.getGoods());
        // 构建地址映射，用于快速查找物流订单中的地址信息
        Map<String, KwtLogisticsOrderAddress> addressMap = buildAddressMap(logisticsOrderData.getAddresses());
        // 获取订单映射，用于快速查找物流订单信息
        Map<Long, KwtLogisticsOrder> orderMap = logisticsOrderData.getOrders();

        // 使用Stream流处理订单列表，将每个订单转换为MapVehicleVo对象
        return filteredOrders.stream()
                .map(order -> buildMapVehicleVo(
                        order, wOrderIdSubtaskMap, unitMap, goodsMap,
                        locationInfoMap, exceptionCountMap, truckIdMap, energyTypeMap,
                        addressMap, orderMap))
                .collect(Collectors.toList());
    }

    /**
     * 构建单位映射
     */
    private Map<String, KwtLogisticsOrderUnit> buildUnitMap(List<KwtLogisticsOrderUnit> units) {
        if (CollectionUtils.isEmpty(units)) {
            return Collections.emptyMap();
        }

        return units.stream()
                .filter(unit -> unit.getLOrderId() != null && unit.getUnitType() != null)
                .collect(Collectors.toMap(
                        unit -> unit.getLOrderId() + "_" + unit.getUnitType(),
                        Function.identity(),
                        (k1, k2) -> k1));
    }

    /**
     * 构建商品映射
     */
    private Map<Long, KwtLogisticsOrderGoods> buildGoodsMap(List<KwtLogisticsOrderGoods> goodsList) {
        if (CollectionUtils.isEmpty(goodsList)) {
            return Collections.emptyMap();
        }

        return goodsList.stream()
                .filter(goods -> goods.getLOrderId() != null)
                .collect(Collectors.toMap(KwtLogisticsOrderGoods::getLOrderId, Function.identity(), (k1, k2) -> k1));
    }

    /**
     * 构建地址映射
     */
    private Map<String, KwtLogisticsOrderAddress> buildAddressMap(List<KwtLogisticsOrderAddress> addresses) {
        if (CollectionUtils.isEmpty(addresses)) {
            return Collections.emptyMap();
        }

        return addresses.stream()
                .collect(Collectors.toMap(
                        x -> x.getLOrderId() + "_" + x.getAddressType(),
                        Function.identity(),
                        (k1, k2) -> k1));
    }

    /**
     * 物流订单数据容器
     */
    @Data
    private static class LogisticsOrderData {
        private List<KwtLogisticsOrderUnit> units;
        private List<KwtLogisticsOrderGoods> goods;
        private List<KwtLogisticsOrderAddress> addresses;
        private Map<Long, KwtLogisticsOrder> orders;
    }


    /**
     * 根据查询条件获取运单ID集合
     * 支持按托运单位、承运单位和物流订单号进行筛选
     *
     * @param req   查询请求参数
     * @param allEnt 初始企业ID集合
     * @return 符合条件的运单ID集合
     */
    @NotNull
    private Set<Long> getWayOrderIds(MapVehicleQueryReq req, Set<Long> allEnt) {
        Set<Long> wayOrderIds = Sets.newHashSet();
        
        // 添加查询条件中的托运单位和承运单位到企业ID集合中
        if (req.getConsignEntId() != null) {
            allEnt.add(req.getConsignEntId());
        }
        if (req.getCarrierEntId() != null) {
            allEnt.add(req.getCarrierEntId());
        }

        // 根据企业ID集合查询运单
        if (CollectionUtils.isNotEmpty(allEnt)) {
            // 第一步：从物流订单单位表查询符合条件的物流订单ID
            List<KwtLogisticsOrderUnit> allUnits = kwtLogisticsOrderUnitRepository.list(
                    Wrappers.<KwtLogisticsOrderUnit>lambdaQuery()
                            .eq(KwtLogisticsOrderUnit::getDelFlag, 0)
                            .in(KwtLogisticsOrderUnit::getEntId, allEnt)
                            .in(KwtLogisticsOrderUnit::getUnitType, Arrays.asList(1, 2, 3))); // 1-托运单位, 2-承运单位, 3-其他单位

            if (CollectionUtils.isEmpty(allUnits)) {
                return Set.of();
            }

            // 筛选当前登录用户企业ID相关的物流订单ID
            Set<Long> userRelatedLogisticsOrderIds = allUnits.stream()
                    .filter(x -> Objects.equals(x.getEntId(), LoginUserHolder.getEntId()))
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .collect(Collectors.toSet());

            // 获取所有符合条件的物流订单ID（必须同时在allUnits和userRelatedLogisticsOrderIds中）
            Set<Long> lOrderIds = allUnits.stream()
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .filter(userRelatedLogisticsOrderIds::contains)
                    .collect(Collectors.toSet());

            if (CollectionUtils.isEmpty(lOrderIds)) {
                return Set.of();
            }

            // 第二步：根据物流订单ID查询子运单
            List<KwtWaybillOrderSubtask> subtasks = kwtWaybillOrderSubtaskRepository.list(
                    Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
                            .eq(KwtWaybillOrderSubtask::getDelFlag, 0)
                            .in(KwtWaybillOrderSubtask::getLOrderId, lOrderIds));

            if (CollectionUtils.isEmpty(subtasks)) {
                return Set.of();
            }

            // 第三步：获取运单ID
            wayOrderIds = subtasks.stream()
                    .map(KwtWaybillOrderSubtask::getWOrderId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            if (CollectionUtils.isEmpty(wayOrderIds)) {
                return Set.of();
            }
        }

        // 如果请求中包含物流订单号，则单独查询该订单下的运单
        if (StringUtils.isNotBlank(req.getLogisticOrderNo())) {
            // 获取物流订单ID
            KwtLogisticsOrder logOrder = kwtLogisticsOrderRepository.queryByLogisticOrderId(req.getLogisticOrderNo());
            if (Objects.isNull(logOrder)) {
                return Set.of();
            }
            
            // 根据物流订单ID查询子运单
            List<KwtWaybillOrderSubtask> subtasks = kwtWaybillOrderSubtaskRepository.queryByLogId(logOrder.getId());
            
            if (CollectionUtils.isNotEmpty(subtasks)) {
                // 将新查询到的运单ID添加到结果集合中
                Set<Long> additionalWayOrderIds = subtasks.stream()
                        .map(KwtWaybillOrderSubtask::getWOrderId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                
                wayOrderIds.addAll(additionalWayOrderIds);
            }
        }

        return wayOrderIds;
    }

    @NotNull
    private static Date getStartDate(String date) {
        Date startDate;
        if (StringUtils.isBlank(date)) {
            startDate = DateUtils.getStartOfDay(new Date());
        } else {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                startDate = sdf.parse(date);
                startDate = DateUtils.getStartOfDay(startDate);
            } catch (Exception e) {
                log.error("解析开始日期失败", e);
                startDate = DateUtils.getStartOfDay(new Date());
            }
        }
        return startDate;
    }
    @NotNull
    private static Date getEndDate(String date) {
        Date endDate;
        if (StringUtils.isBlank(date)) {
            endDate = DateUtils.getEndOfDay(new Date());
        } else {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                endDate = sdf.parse(date);
                endDate = DateUtils.getEndOfDay(endDate);
            } catch (Exception e) {
                log.error("解析结束日期失败", e);
                endDate = DateUtils.getEndOfDay(new Date());
            }
        }
        return endDate;
    }

    /**
     * 批量查询车辆定位信息
     */
    private Map<String, VehicleLocationInfo> queryVehicleLocationBatch(Map<Long, String> truckIdAndTruckNoMap) {
        Map<String, VehicleLocationInfo> locationInfoMap = new HashMap<>();
        LocalDateTime now = LocalDateTime.now();
        log.info("获取配置时间：{}", urlConfigProperties.getMinute());
        LocalDateTime thirtyMinutesAgo = now.minusMinutes(urlConfigProperties.getMinute());
        if (MapUtils.isEmpty(truckIdAndTruckNoMap)){
            return locationInfoMap;
        }
        truckIdAndTruckNoMap.forEach((truckId, truckNo) -> {
            try {
                VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                vehicleDataDTO.setCarNo(Objects.isNull(truckId) ? "0" : String.valueOf(truckId));
                BaseIotResult<VehicleReturnData> result = vehicleTraceClient.queryRealTimeLocation(vehicleDataDTO);
                log.info("查询车辆数据中台响应定位信息：{}", JSON.toJSONString( result));
                VehicleLocationInfo locationInfo = new VehicleLocationInfo();

                if (result != null && StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
                    VehicleReturnData vehicleData = result.getData();

                    // 判断定位状态
                    if (vehicleData.getTs() != null && vehicleData.getTs().toLocalDateTime().isAfter(thirtyMinutesAgo)) {
                        locationInfo.setLocationStatus(1);
                    } else {
                        locationInfo.setLocationStatus(0);
                    }

                    locationInfo.setLongitude(vehicleData.getLongitude());
                    locationInfo.setLatitude(vehicleData.getLatitude());
                    if (vehicleData.getTs() != null) {
                        locationInfo.setLocationTime(vehicleData.getTs().toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    }
                    locationInfo.setStatus(vehicleData.getStatus());
                } else {
                    locationInfo.setLocationStatus(0);
                }

                locationInfoMap.put(truckNo, locationInfo);
            } catch (Exception e) {
                log.warn("查询车辆定位信息异常, 车牌号: {}", truckNo, e);
                VehicleLocationInfo locationInfo = new VehicleLocationInfo();
                locationInfo.setLocationStatus(0);
                locationInfoMap.put(truckNo, locationInfo);
            }
        });
        
        return locationInfoMap;
    }
    
    /**
     * 批量查询运单轨迹数据并统计异常数量
     * 通过调用VehicleTraceClient#queryVehicleDataList查询轨迹，统计alarmCode不为空的数据为异常
     *
     * @param wOrderNos 运单号列表
     * @return 运单号对应的异常数量 Map
     */
    private Map<String, Integer> countExceptionsByTraceData(List<String> wOrderNos) {
        Map<String, Integer> exceptionCountMap = new HashMap<>();
        
        if (CollectionUtils.isEmpty(wOrderNos)) {
            return exceptionCountMap;
        }
        
        // 批量查询每个运单的轨迹数据
        for (String wOrderNo : wOrderNos) {
            try {
                VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                vehicleDataDTO.setWOrderNo(wOrderNo);
                
                // 调用Feign接口查询轨迹列表
                BaseIotResult<List<VehicleReturnData>> result =
                        vehicleTraceClient.queryVehicleDataList(vehicleDataDTO);
                log.info("查询车辆数据中台响应轨迹数据：{}", JSON.toJSONString( result));
                if (result != null && StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
                    List<com.sckw.transport.api.model.dto.VehicleReturnData> traceDataList = result.getData();
                    
                    // 统计alarmCode不为null且不为0的记录数量（表示有异常报警）
                    int exceptionCount = (int) traceDataList.stream()
                            .filter(data -> StringUtils.equals(data.getStatus(),"0"))
                            .count();
                    
                    exceptionCountMap.put(wOrderNo, exceptionCount);
                    log.debug("运单号: {}, 异常数量: {}", wOrderNo, exceptionCount);
                } else {
                    log.warn("查询运单轨迹数据失败或返回空数据, 运单号: {}", wOrderNo);
                    exceptionCountMap.put(wOrderNo, 0);
                }
            } catch (Exception e) {
                log.error("查询运单轨迹数据异常, 运单号: {}", wOrderNo, e);
                exceptionCountMap.put(wOrderNo, 0);
            }
        }
        
        return exceptionCountMap;
    }
    
    /**
     * 构建地图车辆VO
     */
    private MapVehicleVo buildMapVehicleVo(KwtWaybillOrder order,
                                           Map<Long, KwtWaybillOrderSubtask> subtaskMap,
                                           Map<String, KwtLogisticsOrderUnit> unitMap,
                                           Map<Long, KwtLogisticsOrderGoods> goodsMap,
                                           Map<String, VehicleLocationInfo> locationInfoMap,
                                           Map<String, Integer> exceptionCountMap,
                                           Map<Long, RTruckVo> truckIdMap,
                                           Map<String, SysDictResDto> energyTypeMap,
                                           Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap,
                                           Map<Long, KwtLogisticsOrder> logisticsOrderMap) {
        MapVehicleVo vo = new MapVehicleVo();
        
        // 车辆和司机信息
        vo.setTruckNo(order.getTruckNo());
        vo.setTruckId(order.getTruckId());
        vo.setDriverId(order.getDriverId());
        vo.setDriverName(order.getDriverName());
        vo.setDriverPhone(order.getDriverPhone());
        vo.setWayOrderId(order.getId());
        vo.setWayOrderNo(order.getWOrderNo());
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(CarWaybillV1Enum.geDesc(order.getStatus()));
        
        // 子运单信息
        KwtWaybillOrderSubtask subtask = subtaskMap.get(order.getId());
        if (subtask != null) {
            vo.setLogisticOrderId(subtask.getLOrderId());
            KwtLogisticsOrder logisticsOrder = logisticsOrderMap.getOrDefault(subtask.getLOrderId(), new KwtLogisticsOrder());
            vo.setLogisticOrderNo(logisticsOrder.getLOrderNo());
            vo.setLoadAmount(subtask.getLoadAmount());
            vo.setEntrustAmount(subtask.getEntrustAmount());
            vo.setUnit(subtask.getUnit());
            
            // 装货重量/任务量
            String loadWeight = String.format("%s%s / %s%s",
                    subtask.getLoadAmount() != null ? subtask.getLoadAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00",
                    subtask.getUnit() != null ? subtask.getUnit() : "",
                    subtask.getEntrustAmount() != null ? subtask.getEntrustAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00",
                    subtask.getUnit() != null ? subtask.getUnit() : "");
            vo.setLoadWeight(loadWeight);
            
            // 托运单位
            KwtLogisticsOrderUnit consignUnit = unitMap.get(subtask.getLOrderId() + "_1");
            if (consignUnit != null) {
                vo.setConsignUnit(consignUnit.getFirmName());
            }
            
            // 承运单位
            KwtLogisticsOrderUnit carrierUnit = unitMap.get(subtask.getLOrderId() + "_2");
            if (carrierUnit != null) {
                vo.setCarrierUnit(carrierUnit.getFirmName());
            }
            
            // 商品信息
            KwtLogisticsOrderGoods goods = goodsMap.get(subtask.getLOrderId());
            if (goods != null) {
                vo.setGoodsInfo(goods.getGoodsName());
            }
        }
        
        // 定位信息
        VehicleLocationInfo locationInfo = locationInfoMap.get(order.getTruckNo());
        if (locationInfo != null) {
            vo.setLocationStatus(locationInfo.getLocationStatus());
            vo.setLocationStatusDesc(locationInfo.getLocationStatus() == 1 ? "在线" : "离线");
            vo.setLongitude(locationInfo.getLongitude());
            vo.setLatitude(locationInfo.getLatitude());
            vo.setLocation(locationInfo.getLocation());
            vo.setLocationTime(locationInfo.getLocationTime());
        } else {
            vo.setLocationStatus(0);
            vo.setLocationStatusDesc("离线");
        }
        
        // 任务开始时间
        vo.setTaskStartTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(order.getCreateTime()));
        
        // 计算任务耗时（分钟）
        Date startTime =  order.getCreateTime();
        Date endTime = new Date();
        if (Objects.equals(order.getStatus(), CarWaybillV1Enum.COMPLETED.getCode())){
            endTime = order.getUpdateTime() != null ? order.getUpdateTime() : new Date();
        }
        long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
        vo.setTaskDuration(duration);
        
        // 从异常表查询该运单的异常数量
        Integer exceptionCount = exceptionCountMap.getOrDefault(order.getWOrderNo(), 0);
        vo.setExceptionCount(exceptionCount);
        Long logisticId = Optional.ofNullable(subtask).map(KwtWaybillOrderSubtask::getLOrderId)
                .orElse(null);
        KwtLogisticsOrderAddress loadAdd = logisticsOrderAddressMap.getOrDefault(logisticId + "_" + AddressTypeEnum.SHIPMENT.getCode(), new KwtLogisticsOrderAddress());
        vo.setLoadAddress(loadAdd.getDetailAddress());
        KwtLogisticsOrderAddress unLoadAdd = logisticsOrderAddressMap.getOrDefault(logisticId + "_" + AddressTypeEnum.TAKE.getCode(), new KwtLogisticsOrderAddress());
        vo.setUnloadAddress(unLoadAdd.getDetailAddress());
        RTruckVo truckVo = truckIdMap.getOrDefault(order.getTruckId(), new RTruckVo());
        vo.setEnergyType(Objects.isNull(truckVo.getEnergyType())? "":String.valueOf(truckVo.getEnergyType()));
        SysDictResDto dictResDto = energyTypeMap.getOrDefault(String.valueOf(truckVo.getEnergyType()), new SysDictResDto());
        vo.setEnergyTypeDesc(dictResDto.getLabel());
        vo.setStartLng(loadAdd.getLng());
        vo.setStartLat(loadAdd.getLat());
        vo.setEndLng(unLoadAdd.getLng());
        vo.setEndLat(unLoadAdd.getLat());
        return vo;
    }
    
    /**
     * 车辆定位信息内部类
     */
    @Data
    private static class VehicleLocationInfo {
        private Integer locationStatus;
        private String longitude;
        private String latitude;
        private String location;
        private String locationTime;
        private String status;
    }

    @NotNull
    private Set<Long> getAllEnt() {
        Set<Long> allEnt = Sets.newHashSet();
        //根据企业类型查询企业

        allEnt.add(LoginUserHolder.getEntId());
//        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(LoginUserHolder.getUserId());
//        if (Objects.nonNull(entCacheResDto)) {
//            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
//            List<EntCacheResDto> child = entCacheResDto1.getChild();
//            if (com.sckw.core.utils.CollectionUtils.isNotEmpty(child)) {
//                allEnt.addAll(child.stream()
//                        .map(EntCacheResDto::getId).toList());
//            }
//        }
        return allEnt;
    }


    /**
     * 生成车辆轨迹数据（异步执行）
     * @param req 生成轨迹请求参数
     */
   // @Async("traceTaskExecutor")
    public void generateTrace(GenerateTraceReq req) {
        generateTraceInternal(req);
    }

    /**
     * 生成车辆轨迹数据（内部方法，包含事务）
     * @param req 生成轨迹请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void generateTraceInternal(GenerateTraceReq req) {
        log.info("生成车辆轨迹参数：{}", JSON.toJSONString(req));
        LocalDate date = LocalDate.parse(req.getDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDateTime startDateTime = date.atStartOfDay();
        LocalDateTime endDateTime = date.atTime(23, 59, 59);
        List<VehicleReturnData> vehicleReturnDataList = getVehicleReturnDataList(req.getWayOrderNo());
        if (CollectionUtils.isNotEmpty(vehicleReturnDataList)){
            vehicleReturnDataList.forEach(vehicleReturnData ->{
                Timestamp ts = vehicleReturnData.getTs();
                if (ts != null) {
                    LocalDateTime dataTime = ts.toLocalDateTime();
                    if (dataTime.isAfter(startDateTime) && dataTime.isBefore(endDateTime)) {
                        throw new BusinessException("当前时间段已生成轨迹数据,请勿重新生成");
                    }
                }
            });
        }

        // 校验当前位置格式，必须为经度,纬度格式
        String[] location = req.getCurrentLocation().split(",");
        if (location.length != 2) {
            throw new BusinessException("当前位置格式错误，应为：经度,纬度");
        }
        
        // 提取经度和纬度
        String longitude = location[0];
        String latitude = location[1];

        // 根据运单号查询运单信息
        KwtWaybillOrder order = kwtWaybillOrderRepository.queryByWayOrderNo(req.getWayOrderNo());
        if (Objects.isNull(order)){
            throw new BusinessException("运单不存在");
        }
        
        // 查询子运单信息
        KwtWaybillOrderSubtask subOrders = kwtWaybillOrderSubtaskRepository.queryByBillOrderId(order.getId());
        if (Objects.isNull(subOrders)){
            throw new BusinessException("子运单不存在");
        }
        //查询运单装卸货地址
        List<KwtWaybillOrderAddress> addressList = kwtWaybillOrderAddressRepository.queryByWOrderId(order.getId());
        if (CollectionUtils.isEmpty(addressList)){
            throw new BusinessException("运单地址不存在");
        }
        String startLng= "";
        String startLat= "";
        String endLng =  "";
        String endLat = "";
        for (KwtWaybillOrderAddress address : addressList) {
            if (Objects.equals(address.getAddressType(), AddressTypeEnum.SHIPMENT.getCode())) {
                startLng = address.getLng();
                startLat = address.getLat();
            }
            if (Objects.equals(address.getAddressType(), AddressTypeEnum.TAKE.getCode())) {
                endLng = address.getLng();
                endLat = address.getLat();
            }
        }
        List<Integer> statusList = Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.COMPLETION_LOADING.getCode());
        if (!statusList.contains(order.getStatus())){
             endLng =  longitude;
             endLat = latitude;
        }

        LocUtils.RouteResult routeResult = generateRoutePointsWithDuration(startLng, startLat, endLng, endLat, date);
        if (routeResult == null || com.sckw.core.utils.StringUtils.isBlank(routeResult.getPointInfo())) {
            log.error("高德API生成轨迹点位失败，起点: {},{} 终点: {},{}", startLng, startLat, endLng, endLat);
            throw new BusinessException("生成轨迹失败：高德API生成轨迹点位失败");
        }
        List<LocUtils.RoutePoint> routePoints = JSON.parseArray(routeResult.getPointInfo(), LocUtils.RoutePoint.class);
        if (CollectionUtils.isEmpty(routePoints)) {
            log.error("高德API生成轨迹点位失败，起点: {},{} 终点: {},{}", startLng, startLat, endLng, endLat);
            throw new BusinessException("生成轨迹失败：高德API生成轨迹点位为空");
        }

        // 通过车牌ID查询所属车队信息
        RFleetVo fleetByTruckId = fleetService.findFleetByTruckId(order.getTruckId());
        
        // 查询物流订单信息
        KwtLogisticsOrder logisticsOrder = kwtLogisticsOrderRepository.queryByLogisticsOrderId(subOrders.getLOrderId());

        // 构造要发送给数据中台的轨迹数据请求
        // 输入的日期字符串
       // LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDateTime dateTime = date.atTime(LocalTime.now());
        
        // 如果存在异常类型集合，根据异常类型数量随机选择对应数量的轨迹点来设置异常
        Random random = new Random();
        // 轨迹点索引 -> 异常类型 的映射
        Map<Integer, Integer> exceptionPointMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(req.getExceptionType()) && routePoints.size() > 0) {
            List<Integer> exceptionTypes = req.getExceptionType();
            int exceptionTypeCount = exceptionTypes.size();
            
            // 异常类型有几种，就随机生成几种异常节点
            // 随机选择对应数量的轨迹点索引（不重复）
            Set<Integer> selectedIndexes = new HashSet<>();
            while (selectedIndexes.size() < exceptionTypeCount && selectedIndexes.size() < routePoints.size()) {
                selectedIndexes.add(random.nextInt(routePoints.size()));
            }
            
            // 将每个异常类型分配给一个轨迹点
            List<Integer> selectedIndexList = new ArrayList<>(selectedIndexes);
            Collections.shuffle(selectedIndexList, random); // 打乱顺序，确保随机分配
            
            for (int j = 0; j < exceptionTypeCount && j < selectedIndexList.size(); j++) {
                int pointIndex = selectedIndexList.get(j);
                int exceptionType = exceptionTypes.get(j);
                exceptionPointMap.put(pointIndex, exceptionType);
            }
            
            log.info("异常类型数量：{}，随机选择{}个轨迹点设置异常，轨迹点索引和异常类型映射：{}", 
                    exceptionTypeCount, exceptionPointMap.size(), exceptionPointMap);
        }
        
        for (int i = 0; i < routePoints.size(); i++) {
            LocUtils.RoutePoint routePoint = routePoints.get(i);
            VehiclesTrajectoryReq vehiclesTrajectoryReq = getVehiclesTrajectoryReq(req, order, routePoint.getLongitude(), routePoint.getLatitude(), logisticsOrder, fleetByTruckId);
            LocalDateTime localDateTime = dateTime.plusSeconds(i * 5L);
            Timestamp timestamp = Timestamp.valueOf(localDateTime);
            vehiclesTrajectoryReq.setTs(timestamp);
            
            // 如果当前轨迹点被选中设置异常，则使用对应的异常类型
            Integer selectedExceptionType = exceptionPointMap.get(i);
            if (selectedExceptionType != null) {
                // 设置状态为异常（异常类型的code转换为字符串）
                vehiclesTrajectoryReq.setStatus(String.valueOf(selectedExceptionType));
                log.info("轨迹点[{}]设置异常类型：{}", i, selectedExceptionType);
            } else {
                // 正常状态
                vehiclesTrajectoryReq.setStatus("0");
            }
            
            try {
                // 调用数据中台保存轨迹数据
                log.info("调用数据中台保存车辆轨迹数据：{}", JSON.toJSONString(vehiclesTrajectoryReq));
                BaseIotResult<Void> result = vehicleTraceClient.saveVehicleData(vehiclesTrajectoryReq);
                if (!Objects.equals(result.getCode(), "0")) {
                    log.error("保存车辆轨迹数据失败：{}", result.getMessage());
                    throw new BusinessException("生成轨迹失败：" + result.getMessage());
                }

                // 如果当前轨迹点有异常类型，则保存到本地车辆异常表
                if (selectedExceptionType != null) {
                    saveException(req, order, routePoint.getLongitude(), routePoint.getLatitude(), selectedExceptionType, timestamp);
                }

                log.info("生成车辆轨迹成功，运单号：{}，车牌号：{}，轨迹点：{}", req.getWayOrderNo(), req.getTruckNo(), i);
            } catch (Exception e) {
                log.error("生成车辆轨迹异常：", e);
                throw new BusinessException("生成轨迹失败：" + e.getMessage());
            }
        }

    }


    private LocUtils.RouteResult generateRoutePointsWithDuration(String startLng, String startLat, String endLng, String endLat,LocalDate date) {
        try {
            log.info("开始调用高德API生成轨迹点位和耗时，起点: {},{} 终点: {},{}",
                    startLng, startLat, endLng, endLat);

            // 调用高德驾车路径规划API，生成20个轨迹点位和耗时
            LocUtils.RouteResult routeResult = com.sckw.core.utils.LocUtils.getDrivingRoutePointsWithDuration(
                    startLng,
                    startLat,
                    endLng,
                    endLat,
                    20,
                     date
            );

            if (routeResult != null && com.sckw.core.utils.StringUtils.isNotBlank(routeResult.getPointInfo())) {
                log.info("高德API生成轨迹点位成功，耗时: {}秒", routeResult.getDuration());
            } else {
                log.warn("高德API生成轨迹点位失败或返回空数据");
            }

            return routeResult;
        } catch (Exception e) {
            log.error("调用高德API生成轨迹点位异常", e);
            return null;
        }
    }
    /**
     * 保存单个异常信息到车辆异常表
     * @param req 生成轨迹请求参数
     * @param order 运单信息
     * @param longitude 经度
     * @param latitude 纬度
     * @param exceptionType 异常类型
     * @param exceptionTime 异常时间
     */
    private void saveException(GenerateTraceReq req, KwtWaybillOrder order, String longitude, String latitude, Integer exceptionType, Timestamp exceptionTime) {
        if (exceptionType == null) {
            return;
        }
        
        // 保存到车辆异常表
        KwtVehicleException vehicleException = new KwtVehicleException();
        vehicleException.setEntId(order.getEntId());
        vehicleException.setTruckId(order.getTruckId());
        vehicleException.setTruckNo(req.getTruckNo());
        vehicleException.setWOrderId(order.getId());
        vehicleException.setWOrderNo(req.getWayOrderNo());
        vehicleException.setDriverId(order.getDriverId());
        vehicleException.setDriverName(order.getDriverName());
        vehicleException.setDriverPhone(order.getDriverPhone());
        vehicleException.setExceptionType(exceptionType);
        vehicleException.setDescription(VehicleExceptionTypeEnum.getName(exceptionType));
        vehicleException.setLocation(req.getExceptionLocation());
        vehicleException.setLongitude(longitude);
        vehicleException.setLatitude(latitude);
        vehicleException.setExceptionTime(exceptionTime != null ? new Date(exceptionTime.getTime()) : new Date());
        vehicleException.setCreateBy(LoginUserHolder.getUserId());
        vehicleException.setCreateTime(new Date());
        vehicleException.setUpdateBy(LoginUserHolder.getUserId());
        vehicleException.setUpdateTime(new Date());
        vehicleException.setDelFlag(0);
        
        // 保存异常信息
        kwtVehicleExceptionRepository.save(vehicleException);
        log.info("保存车辆异常信息成功，运单号：{}，异常类型：{}，位置：{},{}", req.getWayOrderNo(), exceptionType, longitude, latitude);
    }

    @NotNull
    private static VehiclesTrajectoryReq getVehiclesTrajectoryReq(GenerateTraceReq req, KwtWaybillOrder order, String longitude, String latitude, KwtLogisticsOrder logisticsOrder, RFleetVo fleetByTruckId) {
        VehiclesTrajectoryReq vehiclesTrajectoryReq = new VehiclesTrajectoryReq();

        vehiclesTrajectoryReq.setMobile(order.getDriverPhone());
        vehiclesTrajectoryReq.setTruckNo(req.getTruckNo());
        vehiclesTrajectoryReq.setLongitude(longitude);
        vehiclesTrajectoryReq.setLatitude(latitude);
        vehiclesTrajectoryReq.setSpeed(60.0f);
        vehiclesTrajectoryReq.setGpsStatus("60");
        vehiclesTrajectoryReq.setDirection(30.0f);
        vehiclesTrajectoryReq.setFuelLevel(20.0f);
        vehiclesTrajectoryReq.setMileage("60");
        vehiclesTrajectoryReq.setEngineTemp(40.0f);
        vehiclesTrajectoryReq.setBatteryVoltage(30.0f);
        vehiclesTrajectoryReq.setStatus("0");
        vehiclesTrajectoryReq.setAlarmCode("0");
        vehiclesTrajectoryReq.setWOrderNo(req.getWayOrderNo());
        vehiclesTrajectoryReq.setWayOrderNo(req.getWayOrderNo());
        vehiclesTrajectoryReq.setLOrderNo(Optional.ofNullable(logisticsOrder).map(KwtLogisticsOrder::getLOrderNo).orElse( ""));
        VehiclesTrajectoryReq.VehicleDataVO vehicleDataVO = new VehiclesTrajectoryReq.VehicleDataVO();
        vehicleDataVO.setCarNo(Objects.isNull(order.getTruckId()) ? "0" : String.valueOf(order.getTruckId()));
        if (fleetByTruckId != null){
            vehicleDataVO.setFleetId(Objects.nonNull(fleetByTruckId.getId())?fleetByTruckId.getId().toString():"");
            vehicleDataVO.setFleetName(fleetByTruckId.getName());
        }
        vehiclesTrajectoryReq.setVehicleDataVO(vehicleDataVO);
        return vehiclesTrajectoryReq;
    }
}