package com.sckw.transport.service;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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.contract.api.feign.LogisticsScoreFeignService;
import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
import com.sckw.contract.api.model.vo.KwcContractLogisticsDto;
import com.sckw.contract.api.model.vo.TradeContractGoodsDto;
import com.sckw.contract.api.model.vo.TradeContractUnitDto;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.BusinessPlatfromException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
import com.sckw.core.model.enums.*;
import com.sckw.core.model.page.PageHelperUtil;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.model.vo.TableTop;
import com.sckw.core.utils.*;
import com.sckw.core.web.constant.CommonConstants;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.BaseIotResult;
import com.sckw.core.web.response.BaseResult;
import com.sckw.core.web.response.HttpResult;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.excel.utils.DateUtil;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.fleet.api.model.dto.RUpdateDriverScoreDto;
import com.sckw.fleet.api.model.vo.*;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.OrderDetailVo;
import com.sckw.order.api.model.TradeOrderContractVo;
import com.sckw.order.api.model.TradeOrderSettlePara;
import com.sckw.payment.api.feign.PaymentFeignService;
import com.sckw.payment.api.model.feign.WalletPayableDto;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.SckwMessage;
import com.sckw.stream.model.UserInfo;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.feign.DataPermissionFeignService;
import com.sckw.system.api.model.dto.req.DataPermissionFilterReqDto;
import com.sckw.system.api.model.dto.res.*;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
import com.sckw.transport.api.feign.VehicleTraceClient;
import com.sckw.transport.common.config.UrlConfigProperties;
import com.sckw.transport.dao.*;
import com.sckw.transport.model.*;
import com.sckw.transport.model.dto.*;
import com.sckw.transport.model.enuma.*;
import com.sckw.transport.model.param.WaybillOrderNodeReq;
import com.sckw.transport.model.param.WaybillOrderReq;
import com.sckw.transport.model.param.WaybillOrderResp;
import com.sckw.transport.model.vo.*;
import com.sckw.transport.repository.*;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zk
 * @desc 车辆运单
 * @date 2023/7/19 0019
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class KwtWaybillOrderV1Service {
    @Autowired
    KwtWaybillOrderV1Mapper waybillOrderV1Dao;
    @Autowired
    KwtLogisticsOrderMapper logisticsOrderDao;
    @Autowired
    KwtLogisticsOrderTrackMapper logisticsOrderTrackDao;
    @Autowired
    KwtLogisticsOrderAddressMapper logisticsOrderAddressDao;
    @Autowired
    KwtWaybillOrderAddressMapper waybillOrderAddressDao;
    @Autowired
    KwtWaybillOrderTrackMapper waybillOrderTrackDao;
    @Autowired
    KwtWaybillOrderTicketMapper waybillOrderTicketDao;
    @Autowired
    KwtWaybillOrderSubtaskMapper waybillOrderSubtaskDao;
    @Autowired
    KwtLogisticsOrderAmountMapper logisticsOrderAmountDao;
    @Autowired
    KwtLogisticsOrderGoodsMapper logisticsOrderGoodsDao;
    @Autowired
    KwtLogisticsOrderUnitMapper logisticsOrderUnitDao;
    @Autowired
    KwtWaybillOrderTicketService waybillOrderTicketService;
    @Autowired
    KwtLogisticsOrderGoodsService kwtLogisticsOrderGoodsService;
    @Autowired
    KwtWaybillOrderSubtaskService waybillOrderSubtaskService;
    @Autowired
    KwtCommonService commonService;
    @Resource
    private UrlConfigProperties urlConfigProperties;
    private final KwtWaybillOrderAddressRepository waybillOrderAddressRepository;
    private final KwtWaybillOrderTrackRepository kwtWaybillOrderTrackRepository;
    private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
    private final KwtLogisticsOrderRepository logisticsOrderRepository;
    private final KwtWaybillOrderRepository kwtWaybillOrderRepository;
    private final KwtLogisticsOrderUnitRepository kwtLogisticsOrderUnitRepository;
    private final KwtLogisticsOrderGoodsRepository kwtLogisticsOrderGoodsRepository;
    private final KwtWaybillOrderSubtaskRepository kwtWaybillOrderSubtaskRepository;
    private final KwtLogisticsOrderRepository kwtLogisticsOrderRepository;
    private final KwtWaybillOrderTicketRepository kwtWaybillOrderTicketRepository;
    private final KwtWaybillOrderNodeRepository kwtWaybillOrderNodeRepository;
    private final VehicleTraceClient vehicleTraceClient;

    @Resource
    private StreamBridge streamBridge;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    private RemoteUserService remoteUserService;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 10000)
    private RemoteFleetService remoteFleetService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TradeOrderInfoService tradeOrderInfoService;
    @Autowired
    private PaymentFeignService paymentFeignService;
    @Value("${message.waybill.refuseSendCar.app}")
    private String refuseSendCarAppUrl;
    @Value("${message.waybill.refuseSendCar.pc}")
    private String refuseSendCarPcUrl;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private GoodsInfoService goodsInfoService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteContractService remoteContractService;

    @Autowired
    LogisticsScoreFeignService logisticsScoreFeignService;
    @Resource
    DataPermissionFeignService dataPermissionFeignService;
    @Autowired
    private KwtLogisticsOrderAddressRepository kwtLogisticsOrderAddressRepository;
    // 定义超时时间常量
    private static final long PARALLEL_TIMEOUT_SECONDS = 60;

    /**
     * @param params 请求参数
     * @desc 统计
     * @author zk
     * @date 2024/3/8
     **/
    public List<TableTop> statistics(WaybillOrderQueryDto params) {
        //统计信息
        List<TableTop> tableTops = waybillOrderV1Dao.statistics(params);

        //数据处理
        List<TableTop> topList = new ArrayList<>();
        TableTop top1 = new TableTop();
        top1.setName("全部");
        top1.setTotal(tableTops.stream().mapToInt(TableTop::getTotal).sum());
        topList.add(top1);

        for (CarWaybillTableTopEnum entity : CarWaybillTableTopEnum.values()) {
            TableTop top = new TableTop();
            top.setName(entity.getName());
            top.setValue(entity.getCode());
            top.setTotal(Global.NUMERICAL_ZERO);
            if (entity.getValue() == null) {
                //全部数据
                int totalCount = tableTops.stream().mapToInt(TableTop::getTotal).sum();
                top.setTotal(totalCount);
            } else {
                tableTops.stream().filter(table -> entity.getValue().contains(String.valueOf(table.getValue()))).findAny().ifPresent(tableTop -> top.setTotal(tableTop.getTotal()));
            }
            topList.add(top);
        }
        return topList;
    }

    /**
     * @param params {page：页数、pageSize：每页条数、。。。}
     * @desc 分页查询
     * @author zk
     * @date 2024/3/8
     **/
    public List<WaybillOrderSelectVo> findListPage(WaybillOrderQueryDto params) {
        params.setQueryWstatus(CarWaybillTableTopEnum.getValue(params.getStatus()));
        List<WaybillOrderSelectVo> list = waybillOrderV1Dao.findListPage(params);
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }

        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        //数据处理
        for (WaybillOrderSelectVo waybillOrder : list) {
            findListPageHandle(waybillOrder, unitMap);
            waybillOrder.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
        }
        return list;
    }

    /**
     * @param params {page：页数、pageSize：每页条数、。。。}
     * @desc 分页查询
     * @author zk
     * @date 2024/3/8
     **/
    public PageResult findNdexPage(WaybillOrderQueryDto params) {
        params.setQueryWstatus(CarWaybillTableTopEnum.getValue(params.getStatus()));
        // 设置分页参数
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<WaybillOrderSelectVo> list = waybillOrderV1Dao.findListPage(params);
        PageResult pageResult = PageHelperUtil.getPageResult(new PageInfo<>(list));

        //用户ID
        List<Long> userIds = list.stream().map(WaybillOrderSelectVo::getCreateBy).toList();
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //企业ID
        List<Long> entIds = list.stream().map(WaybillOrderSelectVo::getEntId).toList();
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);

        //数据处理
        List<WaybillOrderNdexVo> data = BeanUtil.copyToList(list, WaybillOrderNdexVo.class);
        for (WaybillOrderNdexVo waybillOrder : data) {
            waybillOrder.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
            waybillOrder.setCreateByName(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getName() : null);
            waybillOrder.setFirmName(ents.get(waybillOrder.getEntId()) != null ? ents.get(waybillOrder.getEntId()).getFirmName() : null);
            //数据处理
            findNdexPageHandle(waybillOrder);
        }
        pageResult.setList(data);
        return pageResult;
    }

    /**
     * @param params {page：页数、pageSize：每页条数、。。。}
     * @desc 分页查询-运营端
     * @author zk
     * @date 2024/3/8
     **/
    public List<WaybillOrderSelectVo> findListPageManagement(WaybillOrderQueryDto params) {
        //客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)) {
                return new ArrayList<>();
            }
            authEntIdList.addAll(ids);
        }
        params.setEntIds(authEntIdList);
        params.setQueryWstatus(CarWaybillTableTopEnum.getValue(params.getStatus()));
        List<WaybillOrderSelectVo> list = waybillOrderV1Dao.findListPage(params);
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }

        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        //数据处理
        for (WaybillOrderSelectVo waybillOrder : list) {
            findListPageHandle(waybillOrder, unitMap);
            waybillOrder.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
        }
        return list;
    }

    /**
     * @param wOrderId 运单ID
     * @desc 运单详情
     * @author zk
     * @date 2024/3/13
     **/
    public HttpResult waybillDetail(Long wOrderId) {
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }

        //子单
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        //运单状态记录
        List<KwtWaybillOrderTrack> tracks = waybillOrderTrackDao.findTrack(wOrderId, null, null, null);
        //用户信息
        List<Long> userIds = tracks.stream().map(KwtWaybillOrderTrack::getCreateBy).toList();
        List<Long> userIdList = new ArrayList<>(NumberConstant.SIXTEEN) {{
            add(waybillOrder.getCreateBy());
        }};
        userIdList.addAll(userIds);
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIdList);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //企业ID
        List<Long> entIds = new ArrayList<>() {{
            add(waybillOrder.getEntId());
        }};
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);
        //车辆信息
        RTruckVo truck = remoteFleetService.findTruck(waybillOrder.getTruckId());

        //返回信息
        WaybillDetailVo waybillDetail = new WaybillDetailVo();
        //地址信息
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByAddresses(wOrderId, null);
        //地址数据处理
        List<Map<String, Object>> addressList = new ArrayList<>(NumberConstant.SIXTEEN);
        for (KwtWaybillOrderAddress address : addresses) {
            //运单子单
            KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
            //物流订单商品信息
            KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
            //榜单信息
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.findWaybillOrderTicketV2(address.getId(), subtask.getUnit());
            Map<String, Object> addressData = new HashMap<>(NumberConstant.SIXTEEN);
            addressData.put("addressType", address.getAddressType());
            addressData.put("addressName", address.getName());
            addressData.put("addressCityName", address.getCityName());
            addressData.put("addressDetail", address.getDetailAddress());
            addressData.put("planTime", DateUtils.format(address.getPlanTime(), DateUtils.FORMAT12));
            addressData.put("entrustAmount", address.getEntrustAmount());
            addressData.put("goodsName", goods != null ? goods.getGoodsName() : null);
            addressData.put("unit", subtask.getUnit());
            addressData.put("unitName", unitMap.get(subtask.getUnit()));
            addressData.put("amount", ticket != null ? ticket.getAmount() : null);
            addressData.put("urls", ticket != null ? FileUtils.spliceBatch(ticket.getUrls()) : null);
            addressData.put("operateStatus", ticket != null);
            addressData.put("operateTime", ticket != null ? DateUtils.format(address.getPlanTime(), DateUtils.FORMAT11) : null);
            addressData.put("status", ticket != null ? ticket.getStatus() : null);
            addressData.put("statusName", ticket != null ? ApproveStatusEnum.getName(ticket.getStatus()) : null);
            addressList.add(addressData);
        }

        //状态数据处理
        List<Map<String, Object>> trackList = new ArrayList<>(NumberConstant.SIXTEEN);
        for (KwtWaybillOrderTrack track : tracks) {
            Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
            trackData.put("status", track.getStatus());
            trackData.put("statusName", CarWaybillEnum.getAlias(track.getStatus()));
            trackData.put("remark", track.getRemark());
            trackData.put("operateTime", DateUtils.format(track.getOperateTime(), DateUtils.DATE_TIME_PATTERN));
            trackData.put("createTime", DateUtils.format(track.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
            trackData.put("createByName", usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getName() : null);
            trackData.put("createByPhone", usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getPhone() : null);
            trackList.add(trackData);
        }

        //物流订单编号
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            waybillDetail.setLOrderNo((StringUtils.isBlank(waybillDetail.getLOrderNo()) ? Global.EMPTY_STRING : Global.COMMA) + logisticsOrder.getLOrderNo());
        }

        //状态轨迹
        List<Map<String, Object>> trajectory = waybillDetailHandle(wOrderId);

        BeanUtils.copyProperties(waybillOrder, waybillDetail);
        waybillDetail.setWOrderId(waybillOrder.getId());
        waybillDetail.setStatusName(CarWaybillEnum.getName(waybillOrder.getStatus()));
        waybillDetail.setCreateByName(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getName() : null);
        waybillDetail.setCreateByPhone(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getPhone() : null);
        waybillDetail.setTrailerNo(truck != null ? truck.getTrailerNo() : null);
        waybillDetail.setTruckType(truck != null ? truck.getTruckType() : null);
        waybillDetail.setFirmName(ents.get(waybillOrder.getEntId()) != null ? ents.get(waybillOrder.getEntId()).getFirmName() : null);
        waybillDetail.setTracks(trackList);
        waybillDetail.setAddresses(addressList);
        waybillDetail.setTrajectory(trajectory);
        waybillDetail.setTypeName(waybillDetail.getType() == NumberConstant.ONE ? "趟次运单" : "循环运单");
        return HttpResult.ok(waybillDetail);
    }

    /**
     * @param params {page：页数、pageSize：每页条数、。。。}
     * @desc 分页查询
     * @author zk
     * @date 2024/3/8
     **/
    public PageResult subtaskSelect(WaybillSubtaskOrderQueryDto params) {
        // 设置分页参数
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<WaybillSubtaskSelectVo> list = waybillOrderSubtaskDao.findListPage(params);

        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);
        //企业ID
        List<Long> entIds = list.stream().map(WaybillSubtaskSelectVo::getEntId).toList();
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //用户ID
        List<Long> userIds = list.stream().map(WaybillSubtaskSelectVo::getCreateBy).toList();
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));

        //数据处理
        for (WaybillSubtaskSelectVo waybillOrder : list) {
            waybillOrder.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
            waybillOrder.setUnitLabel(unitMap.get(waybillOrder.getUnit()));
            waybillOrder.setFirmName(ents.get(waybillOrder.getEntId()) != null ? ents.get(waybillOrder.getEntId()).getFirmName() : null);
            waybillOrder.setCreateByName(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getName() : null);
            waybillOrder.setCreateByPhone(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getPhone() : null);
            waybillOrder.setSendCarWeigh(NumberUtils.parseBigDecimal(waybillOrder.getEntrustAmount()));
            waybillOrder.setDefectiveWeigh(NumberUtils.parseBigDecimal(waybillOrder.getDeficitAmount()));
            waybillOrder.setDeduct(deficitPrice(NumberUtils.parseBigDecimal(waybillOrder.getLoadAmount(), null),
                    NumberUtils.parseBigDecimal(waybillOrder.getDeficitAmount(), null),
                    waybillOrder.getLoss(),
                    waybillOrder.getLossLabel(),
                    waybillOrder.getGoodsPrice()));
        }
        return PageHelperUtil.getPageResult(new PageInfo<>(list));
    }

    /**
     * @param params {page：页数、pageSize：每页条数、。。。}
     * @desc 分页查询
     * @author zk
     * @date 2024/3/8
     **/
    public PageResult transportationCapacitySelect(WaybillSubtaskOrderQueryDto params) {
        // 设置分页参数
        PageHelper.startPage(params.getPage(), params.getPageSize());
        List<WaybillOrderSelectVo> list = waybillOrderV1Dao.findCapacityListPage(params);

        //删除空数据
        if (list.size() == 1 && list.get(NumberConstant.ZERO).getTruckId() == null) {
            list.remove(NumberConstant.ZERO);
        }

        //数据处理
        for (WaybillOrderSelectVo waybillOrder : list) {
            RTruckVo truck = remoteFleetService.findTruck(waybillOrder.getTruckId());
            if (truck != null) {
                Double actualWeight = Optional.ofNullable(truck.getActualWeight()).map(BigDecimal::doubleValue).orElse(0.0);
                waybillOrder.setActualWeight(actualWeight);
            }
        }
        return PageHelperUtil.getPageResult(new PageInfo<>(list));
    }

    /**
     * @param wSubtaskId 运单子单ID
     * @desc 运单详情(物流订单)
     * @author zk
     * @date 2024/3/18
     **/
    public HttpResult waybillSubtaskDetail(Long wSubtaskId) {
        //子单
        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(wSubtaskId);
        if (subtask == null) {
            return HttpResult.error("运单" + wSubtaskId + "不存在，请确认！");
        }

        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(subtask.getWOrderId());
        //用户信息
        List<Long> userIdList = new ArrayList<>(NumberConstant.SIXTEEN) {{
            add(waybillOrder.getCreateBy());
        }};
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIdList);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //企业ID
        List<Long> entIds = new ArrayList<>() {{
            add(waybillOrder.getEntId());
        }};
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);
        //合理损耗单位
        Map<String, Map<String, String>> dictLoss = remoteSystemService.queryDictByType(List.of(DictTypeEnum.TAX_RATE_TYPE.getType()));
        Map<String, String> lossMap = CollectionUtils.isNotEmpty(dictLoss) ? dictLoss.get(DictTypeEnum.TAX_RATE_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        //物流订单
        KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
        //物流订单地址信息
        List<KwtLogisticsOrderAddress> lAddressList = logisticsOrderAddressDao.findByAddresses(subtask.getLOrderId(), null);
        List<Long> addressIds = lAddressList.stream().map(KwtLogisticsOrderAddress::getId).toList();
        //地址信息
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByLAddressIds(subtask.getWOrderId(), addressIds);
        //榜单信息
        List<WaybillTicketVO> tickets = waybillOrderTicketService.agreement(subtask);

        //地址数据处理
        List<Map<String, Object>> addressList = new ArrayList<>(NumberConstant.SIXTEEN);
        for (KwtWaybillOrderAddress address : addresses) {
            //物流订单商品信息
            KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
            //榜单信息
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.findWaybillOrderTicketV2(address.getId(), subtask.getUnit());
            Map<String, Object> addressData = new HashMap<>(NumberConstant.SIXTEEN);
            addressData.put("addressType", address.getAddressType());
            addressData.put("addressName", address.getName());
            addressData.put("addressCityName", address.getCityName());
            addressData.put("addressDetail", address.getDetailAddress());
            addressData.put("planTime", DateUtils.format(address.getPlanTime(), DateUtils.FORMAT12));
            addressData.put("entrustAmount", address.getEntrustAmount());
            addressData.put("goodsName", goods != null ? goods.getGoodsName() : null);
            addressData.put("unit", subtask.getUnit());
            addressData.put("unitName", unitMap.get(subtask.getUnit()));
            addressData.put("amount", ticket != null ? ticket.getAmount() : null);
            addressData.put("urls", ticket != null ? ticket.getUrls() : null);
            addressData.put("operateTime", ticket != null ? DateUtils.format(address.getPlanTime(), DateUtils.FORMAT11) : null);
            addressData.put("operateStatus", ticket != null);
            addressList.add(addressData);
        }

        //返回信息
        WaybillSubtaskDetailVo waybillDetail = new WaybillSubtaskDetailVo();
        BeanUtils.copyPropertiesValue(waybillOrder, waybillDetail);
        BeanUtils.copyPropertiesValue(subtask, waybillDetail);
        waybillDetail.setWOrderId(waybillOrder.getId());
        waybillDetail.setLOrderNo(logisticsOrder.getLOrderNo());
        waybillDetail.setLoss(logisticsOrder.getLoss());
        waybillDetail.setLossUnitLabe(lossMap.get(waybillDetail.getUnit()));
        waybillDetail.setWSubtaskId(subtask.getId());
        waybillDetail.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
        waybillDetail.setUnitLabel(unitMap.get(waybillDetail.getUnit()));
        waybillDetail.setFirmName(ents.get(waybillOrder.getEntId()) != null ? ents.get(waybillOrder.getEntId()).getFirmName() : null);
        waybillDetail.setCreateByName(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getName() : null);
        waybillDetail.setCreateByPhone(usersMap.get(waybillOrder.getCreateBy()) != null ? usersMap.get(waybillOrder.getCreateBy()).getPhone() : null);
        waybillDetail.setAddresses(addressList);
        waybillDetail.setTickets(tickets);
        return HttpResult.ok(waybillDetail);
    }

    /**
     * @param waybillOrder 运单信息
     * @param unitMap      字段
     * @desc 分页列表查询
     * @author zk
     * @date 2024/3/13
     **/
    public void findListPageHandle(WaybillOrderSelectVo waybillOrder, Map<String, String> unitMap) {
        //子运单
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(waybillOrder.getWOrderId());
        //子运单
        List<KwtWaybillOrderAddress> loadAddresses = waybillOrderAddressDao.findByAddresses(waybillOrder.getWOrderId(), AddressTypeEnum.SHIPMENT.getCode());
        //子运单
        List<KwtWaybillOrderAddress> unloadAddresses = waybillOrderAddressDao.findByAddresses(waybillOrder.getWOrderId(), AddressTypeEnum.TAKE.getCode());
        //榜单信息
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(waybillOrder.getWOrderId(), null, null);
        List<KwtWaybillOrderTicket> loadTickets = tickets.stream().filter(item -> item.getType().equals(NumberConstant.ONE)).toList();
        List<KwtWaybillOrderTicket> unloadTickets = tickets.stream().filter(item -> item.getType().equals(NumberConstant.TWO)).toList();
        //装货时间
        Optional<KwtWaybillOrderSubtask> startDate = subtasks.stream().min(Comparator.comparing(KwtWaybillOrderSubtask::getLoadTime));
        //卸货时间
        Optional<KwtWaybillOrderSubtask> endDate = subtasks.stream().max(Comparator.comparing(KwtWaybillOrderSubtask::getUnloadTime));
        //实际装货时间
        Optional<KwtWaybillOrderTicket> loadDate = loadTickets.stream().min(Comparator.comparing(KwtWaybillOrderTicket::getOperateTime));
        //实际卸货时间
        Optional<KwtWaybillOrderTicket> unloadDate = unloadTickets.stream().max(Comparator.comparing(KwtWaybillOrderTicket::getOperateTime));
        //装货地点名称
        List<String> loadName = loadAddresses.stream().map(KwtWaybillOrderAddress::getCityName).toList();
        //装货地点
        List<String> loadAddress = loadAddresses.stream().map(KwtWaybillOrderAddress::getDetailAddress).toList();
        //卸货地点点名称
        List<String> unloadName = unloadAddresses.stream().map(KwtWaybillOrderAddress::getCityName).toList();
        //卸货地点
        List<String> unloadAddress = unloadAddresses.stream().map(KwtWaybillOrderAddress::getDetailAddress).toList();

        //数据处理
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            //物流订单
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            //托运企业
            KwtLogisticsOrderUnit procure = logisticsOrderUnitDao.findByUnit(subtask.getLOrderId(), NumberConstant.ONE);
            //承运企业
            KwtLogisticsOrderUnit supply = logisticsOrderUnitDao.findByUnit(subtask.getLOrderId(), NumberConstant.TWO);
            //派单量
            String entrustAmount = subtask.getEntrustAmount() + unitMap.get(subtask.getUnit());
            //实装量
            String loadAmount = subtask.getLoadAmount() != null ? subtask.getLoadAmount() + unitMap.get(subtask.getUnit()) : Global.NUMERICAL_ZERO + unitMap.get(subtask.getUnit());
            //实卸量
            String unloadAmount = subtask.getUnloadAmount() != null ? subtask.getUnloadAmount() + unitMap.get(subtask.getUnit()) : Global.NUMERICAL_ZERO + unitMap.get(subtask.getUnit());
            //实卸量
            String deficitAmount = subtask.getDeficitAmount() != null ? subtask.getDeficitAmount() + unitMap.get(subtask.getUnit()) : Global.NUMERICAL_ZERO + unitMap.get(subtask.getUnit());
            //亏吨重量
            String deficitRealAmount = deficitPrice(BigDecimal.valueOf(NumberUtils.parseDouble(subtask.getLoadAmount())),
                    BigDecimal.valueOf(NumberUtils.parseDouble(subtask.getDeficitAmount())), logisticsOrder.getLoss(),
                    logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice()) + unitMap.get(subtask.getUnit());
            waybillOrder.setEntrustAmount((StringUtils.isBlank(waybillOrder.getEntrustAmount()) ? Global.EMPTY_STRING : Global.COMMA) + entrustAmount);
            waybillOrder.setLoadAmount((StringUtils.isBlank(waybillOrder.getLoadAmount()) ? Global.EMPTY_STRING : Global.COMMA) + loadAmount);
            waybillOrder.setUnloadAmount((StringUtils.isBlank(waybillOrder.getUnloadAmount()) ? Global.EMPTY_STRING : Global.COMMA) + unloadAmount);
            waybillOrder.setDeficitAmount((StringUtils.isBlank(waybillOrder.getDeficitAmount()) ? Global.EMPTY_STRING : Global.COMMA) + deficitAmount);
            waybillOrder.setDeficitRealAmount((StringUtils.isBlank(waybillOrder.getDeficitRealAmount()) ? Global.EMPTY_STRING : Global.COMMA) + deficitRealAmount);
            waybillOrder.setLOrderNo((StringUtils.isBlank(waybillOrder.getLOrderNo()) ? Global.EMPTY_STRING : Global.COMMA) + logisticsOrder.getLOrderNo());
            waybillOrder.setProcureFirmName(procure.getFirmName());
            waybillOrder.setSupplyFirmName(supply.getFirmName());
        }
        waybillOrder.setStartTime(startDate.map(KwtWaybillOrderSubtask::getLoadTime).orElse(null));
        waybillOrder.setEndTime(endDate.map(KwtWaybillOrderSubtask::getUnloadTime).orElse(null));
        waybillOrder.setLoadTime(loadDate.map(KwtWaybillOrderTicket::getOperateTime).orElse(null));
        waybillOrder.setUnloadTime(unloadDate.map(KwtWaybillOrderTicket::getOperateTime).orElse(null));
        waybillOrder.setLoadName(loadName);
        waybillOrder.setLoadAddress(loadAddress);
        waybillOrder.setUnloadName(unloadName);
        waybillOrder.setUnloadAddress(unloadAddress);
    }

    /**
     * @param waybillOrder 运单信息
     * @desc 分页看板查询处理
     * @author zk
     * @date 2024/3/13
     **/
    public void findNdexPageHandle(WaybillOrderNdexVo waybillOrder) {
        /*数据处理*/
        List<Map<String, Object>> trackList = new ArrayList<>();
        for (CarWaybillNdexTopEnum entity : CarWaybillNdexTopEnum.values()) {
            //审核状态
            KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrackV1(waybillOrder.getWOrderId(), entity.getValue());
            Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
            trackData.put("statusName", entity.getName());
            trackData.put("operateStatus", track != null);
            trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
            trackList.add(trackData);
        }
        waybillOrder.setTracks(trackList);

        //榜单信息
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(waybillOrder.getWOrderId(), null, null);
        //数据处理
        List<String> loadUrl = new ArrayList<>(), unloadUrl = new ArrayList<>();
        for (KwtWaybillOrderTicket ticket : tickets) {
            if (ticket.getType().equals(AddressTypeEnum.SHIPMENT.getCode())) {
                loadUrl.add(FileUtils.spliceBatch(ticket.getUrls()));
            } else {
                unloadUrl.add(FileUtils.spliceBatch(ticket.getUrls()));
            }
        }
        waybillOrder.setLoadUrl(loadUrl);
        waybillOrder.setUnloadUrl(unloadUrl);

        //运单-子单
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(waybillOrder.getWOrderId());
        //装货时间
        Optional<KwtWaybillOrderSubtask> unloadDate = subtasks.stream().max(Comparator.comparing(KwtWaybillOrderSubtask::getUnloadTime));
        //卸货时间
        Optional<KwtWaybillOrderSubtask> loadDate = subtasks.stream().min(Comparator.comparing(KwtWaybillOrderSubtask::getLoadTime));
        waybillOrder.setStartTime(loadDate.get().getLoadTime());
        waybillOrder.setEndTime(unloadDate.get().getUnloadTime());
    }

    /**
     * @param wOrderId 运单ID
     * @desc 运单详情状态轴
     * @author zk
     * @date 2024/3/14
     **/
    public List<Map<String, Object>> waybillDetailHandle(Long wOrderId) {
        /*数据处理*/
        List<Map<String, Object>> trackList = new ArrayList<>();
        List<Integer> statusList = CarWaybillDetailEnum.initWaybillStatus();
        //使用for-each循环来遍历Color枚举类的所有值
        for (Integer value : statusList) {
            List<String> asList = Arrays.asList(CarWaybillDetailEnum.getValue(value).split(Global.COMMA));
            for (String status : asList) {
                KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrack(wOrderId, null, null, Integer.valueOf(status));
                Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
                trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
                trackData.put("operateStatus", track != null);
                trackData.put("createTime", track != null ? DateUtils.format(track.getCreateTime(), DateUtils.DATE_TIME_PATTERN) : null);
                trackData.put("status", status);
                trackData.put("statusName", CarWaybillDetailEnum.getName1(Integer.valueOf(status)));
                trackList.add(trackData);
            }
        }

        //运单地址状态处理(到达装货点、已装货、到达卸货点、已卸货)
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByAddresses(wOrderId, null);
        for (KwtWaybillOrderAddress address : addresses) {
            if (address.getAddressType().equals(AddressTypeEnum.SHIPMENT.getCode())) {
                statusList = new ArrayList<>() {{
                    add(CarWaybillEnum.WAIT_LOADING.getCode());
                    add(CarWaybillEnum.COMPLETION_LOADING.getCode());
                }};
            } else {
                statusList = new ArrayList<>() {{
                    add(CarWaybillEnum.WAIT_UNLOADING.getCode());
                    add(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
                }};
            }

            //子单信息
            KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
            for (Integer status : statusList) {
                //状态记录
                KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrack(wOrderId, null, null, status);
                Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
                trackData.put("id", track != null ? track.getId() : null);
                trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
                trackData.put("operateStatus", track != null);
                trackData.put("createTime", track != null ? DateUtils.format(track.getCreateTime(), DateUtils.DATE_TIME_PATTERN) : null);
                trackData.put("status", status);
                trackData.put("statusName", CarWaybillEnum.getName(status));
                trackData.put("planTime", track != null ? DateUtils.format(address.getPlanTime(), DateUtils.DATE_TIME_PATTERN) : null);
                trackData.put("addressName", address.getName());
                trackData.put("addressCityName", address.getCityName());
                trackData.put("addressDetail", address.getDetailAddress());
                trackData.put("lat", address.getLat());
                trackData.put("lng", address.getLng());
                trackList.add(trackData);
            }
        }

        //审核状态
        KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrackV1(wOrderId, CarWaybillDetailEnum.WAIT_APPROVAL.getValue());
        Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
        trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
        trackData.put("operateStatus", track != null);
        trackData.put("createTime", track != null ? track.getCreateTime() : null);
        trackData.put("status", CarWaybillDetailEnum.WAIT_APPROVAL.getCode());
        trackData.put("statusName", CarWaybillDetailEnum.WAIT_APPROVAL.getName());
        trackList.add(trackData);
        return trackList;
    }

    /**
     * @param driverId 司机ID
     * @desc 统计司机任务数(待接单 / 出车 / 执行 / 完结)
     * @author zk
     * @date 2024/3/12
     **/
    public Map<String, Object> findStatisticsCountByDriver(Long driverId, HttpServletRequest request) {
        //专场逻辑
        String accessSpecial = request.getHeader("Access-Special");
        List<Long> specialEntIds = remoteSystemService.queryEntIdsByCode(accessSpecial, EntTypeEnum.carrier());
        return waybillOrderV1Dao.findStatisticsCountByDriver(driverId, specialEntIds);
    }

    /**
     * @param params {driverId 司机ID, busStatus  1待接单/2出车/3执行/4完结, month月份, startTime 开始实际, endTime 结束时间}
     * @desc 任务查询
     * @author zk
     * @date 2024/3/12
     **/
    public List<JSONObject> findWaybillOrderByDriver(Map<String, Object> params, HttpServletRequest request) {
        /*参数处理*/
        params.put("driverId", StringUtils.isBlank(params.get("driverId")) ? LoginUserHolder.getUserId() : params.get("driverId"));
        //专场逻辑
        String accessSpecial = request.getHeader("Access-Special");
        List<Long> specialEntIds = remoteSystemService.queryEntIdsByCode(accessSpecial, EntTypeEnum.carrier());
        params.put("specialEntIds", specialEntIds);
        // 设置分页参数
        PageHelper.startPage(PageResult.getPage(params), PageResult.getPageSize(params));

        /*数据查询**/
        List<WaybillOrderSubtaskVo> waybillOrders = waybillOrderV1Dao.findWaybillOrderSubtask(params);
        //企业ID
        List<Long> entIds = waybillOrders.stream().map(WaybillOrderSubtaskVo::getEntId).toList();
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        //数据处理
        List<JSONObject> list = new ArrayList<>();
        for (WaybillOrderSubtaskVo waybillOrder : waybillOrders) {
            //运单地址信息
            List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByAddresses(waybillOrder.getId(), null);
            List<JSONObject> addressList = new ArrayList<>();
            for (KwtWaybillOrderAddress address : addresses) {
                //运单子单
                KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
                //物流订单商品信息
                KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
                //榜单信息
                KwtWaybillOrderTicket ticket = waybillOrderTicketDao.findWaybillOrderTicketV2(address.getId(), subtask.getUnit());
                //数据组装
                JSONObject addressJson = new JSONObject();
                addressJson.put("wAddressId", address.getId());
                addressJson.put("addressType", address.getAddressType());
                addressJson.put("addressName", address.getName());
                addressJson.put("addressCityName", address.getCityName());
                addressJson.put("addressDetail", address.getDetailAddress());
                addressJson.put("planTime", DateUtils.format(address.getPlanTime(), DateUtils.FORMAT12));
                addressJson.put("entrustAmount", address.getEntrustAmount());
                addressJson.put("goodsName", goods != null ? goods.getGoodsName() : null);
                addressJson.put("unit", subtask.getUnit());
                addressJson.put("unitName", unitMap.get(subtask.getUnit()));
                addressJson.put("amount", ticket != null ? ticket.getAmount() : null);
                addressJson.put("urls", ticket != null ? ticket.getUrls() : null);
                addressJson.put("operateTime", ticket != null ? DateUtils.format(address.getPlanTime(), DateUtils.FORMAT11) : null);
                addressJson.put("approvalStatus", ticket != null ? ticket.getStatus() : null);
                addressList.add(addressJson);
            }

            JSONObject order = JSON.parseObject(JSON.toJSONString(waybillOrder));
            order.put("createTime", DateUtils.format(waybillOrder.getCreateTime(), DateUtils.FORMAT11));
            order.put("typeName", waybillOrder.getType() == NumberConstant.ONE ? "趟次" : "循环");
            order.put("statusName", CarWaybillEnum.getName(waybillOrder.getStatus()));
            order.put("carrierFirmName", ents.get(waybillOrder.getEntId()) != null ? ents.get(waybillOrder.getEntId()).getFirmName() : null);
            order.put("addresses", addressList);
            list.add(order);
        }
        return list;
    }

    /**
     * @desc 获取企业地址信息
     * @author zk
     * @date 2023/9/1
     **/
    public AddressDropListDTO findAddressList() {
        AddressDropListDTO res = new AddressDropListDTO();
        //装货地址树
        List<Integer> loadAddressList = waybillOrderAddressDao.findAddressCodeList(LoginUserHolder.getEntId(), Global.NUMERICAL_ONE);
        //卸货地址树
        List<Integer> unloadAddressList = waybillOrderAddressDao.findAddressCodeList(LoginUserHolder.getEntId(), Global.NUMERICAL_TWO);

        //装货地址下拉列表树
        List<AreaTreeFrontResDto> loadTree = remoteSystemService.queryAreaTreeFrontByCodeList(loadAddressList);
        res.setLoadAddressList(loadTree);
        //卸货地址下拉列表树
        List<AreaTreeFrontResDto> unloadTree = remoteSystemService.queryAreaTreeFrontByCodeList(unloadAddressList);
        res.setUnloadAddressList(unloadTree);
        return res;
    }

    /**
     * @param params 派车参数
     * @desc 派车-多装多卸
     * @author zk
     * @date 2023/7/19
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult sendCarV1(SendCarDto2 params) {
        /*1、校验*/
        HttpResult result = checkWaybillOrderV1(params);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }

        /*2、新增运单相关信息*/
        List<SendCarEntrustDto> sendCarEntrustAll = ranksSave(params);

        /*3、更新承运订单委派信息*/
        List<Long> lOrderIds = editLogisticsOrder(sendCarEntrustAll, params.getType());

        /*4、更新承运订单状态（包括上级承运订单）*/
        editLogisticsOrderStatus(lOrderIds);
        return HttpResult.ok();
    }

    /**
     * @param params 派车请求参数
     * @desc 派车校验
     * @author zk
     * @date 2024/3/4
     **/
    public HttpResult checkWaybillOrderV1(SendCarDto2 params) {
        /*控制校验*/
        if (CollectionUtils.isEmpty(params.getSends())) {
            return HttpResult.error("请选择委派信息！");
        } else {
            for (SendCarInfoDto sendCar : params.getSends()) {
                if (CollectionUtils.isEmpty(sendCar.getEntrusts())) {
                    return HttpResult.error("请选择委派信息！");
                }
            }
        }

        //车辆司机信息
        List<SendCarInfoDto> sends = params.getSends();
        //物流订单ID
        List<Long> lOrderIds = new ArrayList<>();
        //物流订单装卸货地址委派量统计
        Map<Long, BigDecimal> truckTotalEntrustAmount = new HashMap<>(NumberConstant.SIXTEEN);
        for (SendCarInfoDto sendCar : sends) {
            //循环单校验所派车辆是否存在未完结运单
            if (params.getType() == Global.NUMERICAL_TWO) {
                WaybillCountVo countVo = waybillOrderV1Dao.findUnfinishedByTruck(Global.NUMERICAL_TWO, sendCar.getTruckId());
                if (countVo.getTotalExecute() > 0) {
                    //车辆信息
                    RTruckVo truck = remoteFleetService.findTruck(sendCar.getTruckId());
                    String msg = truck != null ? truck.getTruckNo() : Global.EMPTY_STRING;
                    return HttpResult.error("车辆" + msg + "存在未完结的循环运单！");
                }
            }

            //趟次单(循环单默认趟次为1)
            int count = params.getType() == Global.NUMERICAL_ONE ? sendCar.getCount() : Global.NUMERICAL_ONE;
            //运输委托信息
            List<SendCarEntrustDto> entrusts = sendCar.getEntrusts();
            /*数据组装*/
            for (SendCarEntrustDto sendCarEntrust : entrusts) {
                lOrderIds.add(sendCarEntrust.getLOrderId());
                //承运订单该车辆计划运输总量：核定载量 * 趟次
                BigDecimal entrustAmount = BigDecimal.valueOf(sendCarEntrust.getEntrustAmount() * count);
                BigDecimal totalEntrustAmount = truckTotalEntrustAmount.get(sendCarEntrust.getAddressId()) != null
                        ? truckTotalEntrustAmount.get(sendCarEntrust.getAddressId()) : NumberConstant.ZERO_TWO;
                truckTotalEntrustAmount.put(sendCarEntrust.getAddressId(), totalEntrustAmount.add(entrustAmount));
            }
        }
        List<Long> lOrderIdsList = lOrderIds.stream().distinct().toList();

        /*校验物流运单是否可以派车*/
        for (Long lOrderId : lOrderIdsList) {
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(lOrderId);
            if (logisticsOrder == null) {
                return HttpResult.error("订单" + lOrderId + "已不存在！");
            }

            //状态校验
            if (!logisticsOrder.getStatus().equals(LogisticsOrderEnum.WAIT_DELIVERY.getCode())
                    && !logisticsOrder.getStatus().equals(LogisticsOrderEnum.IN_TRANSIT.getCode())) {
                return HttpResult.error("订单" + logisticsOrder.getLOrderNo() + LogisticsOrderEnum.getName(logisticsOrder.getStatus()) + "不能派车！");
            }

            //剩余可运量校验
            BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? new BigDecimal(Global.AMOUNT) : logisticsOrder.getEntrustAmount();
            BigDecimal subcontractAmount = logisticsOrder.getSubcontractAmount() == null ? new BigDecimal(Global.AMOUNT) : logisticsOrder.getSubcontractAmount();
            //历史下游司机委派量 + 分包量
            BigDecimal entrustAmountTotal = entrustAmount.add(subcontractAmount);
            if (entrustAmountTotal.compareTo(logisticsOrder.getAmount()) > 0) {
                return HttpResult.error("订单" + logisticsOrder.getLOrderNo() + "剩余可运量已不能派车！");
            }

            /*校验是车辆委托量否超过物流订单剩余量-趟次*/
            //物流订单地址委托量信息-装货信息
            KwtLogisticsOrderAddress queryAmount = new KwtLogisticsOrderAddress();
            queryAmount.setLOrderId(lOrderId);
            queryAmount.setAddressType(AddressTypeEnum.SHIPMENT.getCode());
            List<KwtLogisticsOrderAmount> logisticsOrderAmounts = logisticsOrderAmountDao.findByAddress(queryAmount);
            for (KwtLogisticsOrderAmount orderAmount : logisticsOrderAmounts) {
                BigDecimal truckEntrustAmount = truckTotalEntrustAmount.get(orderAmount.getLAddressId());
                if (Objects.isNull(truckEntrustAmount)) {
                    continue;
                }
                //剩余可运量 = 当前上游委派量 - 历史下游司机委派量 - 分包量
                BigDecimal surplusAmount = orderAmount.getAmount().subtract(orderAmount.getEntrustAmount()).subtract(orderAmount.getSubcontractAmount());
                if (surplusAmount.doubleValue() < truckEntrustAmount.doubleValue()) {
                    KwtLogisticsOrderAddress address = logisticsOrderAddressDao.selectById(orderAmount.getLAddressId());
                    return HttpResult.error(address.getName() + "剩余量为" + surplusAmount.doubleValue()
                            + "，当前累计派车量为" + truckEntrustAmount.doubleValue() +"，可运量小于累计派车量则不能派车！");
                }
            }
        }
        return HttpResult.ok(truckTotalEntrustAmount);
    }

    /**
     * @param params 派车请求参数
     * @desc 新增运单相关信息
     * @author zk
     * @date 2024/3/5
     **/
    public List<SendCarEntrustDto> ranksSave(SendCarDto2 params) {
        //车辆司机信息
        List<SendCarInfoDto> sends = params.getSends();
        //物流订单对应地址信息(所有)
        List<SendCarEntrustDto> sendCarEntrustAll = new ArrayList<>();
        for (SendCarInfoDto sendCar : sends) {
            //趟次单(循环单默认趟次为1)
            int count = params.getType() == Global.NUMERICAL_ONE ? sendCar.getCount() : Global.NUMERICAL_ONE;
            for (int i = 0; i < count; i++) {
                //新增运单信息
                KwtWaybillOrderV1 waybillOrder = sendCarDriver(sendCar, params.getType());
                //运输委托信息
                List<SendCarEntrustDto> entrusts = sendCar.getEntrusts();
                //物流订单对应地址信息
                Map<Long, List<SendCarEntrustDto>> sendCarEntrusts = new HashMap<>(NumberConstant.SIXTEEN);
                //数据组装-物流订单归类（合并派车）
                for (SendCarEntrustDto sendCarEntrust : entrusts) {
                    //物流订单ID
                    Long lOrderId = sendCarEntrust.getLOrderId();
                    //委派信息
                    List<SendCarEntrustDto> entrustDtos = new ArrayList<>() {{
                        add(sendCarEntrust);
                    }};
                    if (sendCarEntrusts.get(lOrderId) == null) {
                        sendCarEntrusts.put(lOrderId, entrustDtos);
                    } else {
                        entrustDtos.addAll(sendCarEntrusts.get(lOrderId));
                        sendCarEntrusts.put(lOrderId, entrustDtos);
                    }
                    sendCarEntrustAll.add(sendCarEntrust);
                }

                //数据存储
                for (Long lOrderId : sendCarEntrusts.keySet()) {
                    //物流订单关联委派地址信息
                    List<SendCarEntrustDto> sendCars = sendCarEntrusts.get(lOrderId);
                    //物流订单委派量统计
                    BigDecimal entrustAmount = NumberConstant.ZERO_TWO;
                    //物流订单委派装货时间
                    List<Date> loadTime = new ArrayList<>();
                    //物流订单委派卸货时间
                    List<Date> unloadTime = new ArrayList<>();
                    //数据组装-数据统计
                    for (SendCarEntrustDto sendCarEntrust : sendCars) {
                        //委派量
                        BigDecimal amount = BigDecimal.valueOf(sendCarEntrust.getEntrustAmount());
                        //计划装卸货时间
                        Date planTime = sendCarEntrust.getPlanTime();
                        //装货+卸货
                        if (sendCarEntrust.getAddressType() == AddressTypeEnum.SHIPMENT.getCode()) {
                            entrustAmount = entrustAmount.add(amount);
                            loadTime.add(planTime);
                        } else {
                            unloadTime.add(planTime);
                        }
                    }

                    //新增运单子单信息
                    KwtWaybillOrderSubtask subtasks = waybillOrderSubtaskService.sendCarSubtask(waybillOrder, lOrderId, entrustAmount, loadTime, unloadTime);
                    for (SendCarEntrustDto sendCarEntrust : sendCars) {
                        //新增地址信息
                        sendCarAddress(subtasks.getId(), sendCarEntrust, waybillOrder);
                    }
                }

                /*车辆运单状态记录*/
                this.setWaybillOrderTrack(waybillOrder.getId(), null, null, waybillOrder.getUpdateTime(), waybillOrder.getStatus(), null);
            }
        }
        return sendCarEntrustAll;
    }

    /**
     * @param sendCarEntrusts 委派参数
     * @param type            运单类型
     * @desc 更新承运订单委派信息
     * @author zk
     * @date 2024/3/5
     **/
    public List<Long> editLogisticsOrder(List<SendCarEntrustDto> sendCarEntrusts, int type) {
        //物流订单ID
        List<Long> lOrderIds = new ArrayList<>();
        //物流订单对应委派量(所有)
        Map<Long, BigDecimal> lEntrustAmount = new HashMap<>(NumberConstant.SIXTEEN);
        //物流订单地址对应委派量(所有)
        Map<Long, BigDecimal> aEntrustAmount = new HashMap<>(NumberConstant.SIXTEEN);
        //数据组装-数据统计
        for (SendCarEntrustDto sendCarEntrust : sendCarEntrusts) {
            //委派量
            BigDecimal amount = BigDecimal.valueOf(sendCarEntrust.getEntrustAmount());
            //装货+卸货
            if (sendCarEntrust.getAddressType() == AddressTypeEnum.SHIPMENT.getCode()) {
                if (lEntrustAmount.get(sendCarEntrust.getLOrderId()) == null) {
                    lEntrustAmount.put(sendCarEntrust.getLOrderId(), amount);
                } else {
                    BigDecimal entrustAmount = lEntrustAmount.get(sendCarEntrust.getLOrderId()).add(amount);
                    lEntrustAmount.put(sendCarEntrust.getLOrderId(), entrustAmount);
                }
                if (aEntrustAmount.get(sendCarEntrust.getAddressId()) == null) {
                    aEntrustAmount.put(sendCarEntrust.getAddressId(), amount);
                } else {
                    BigDecimal entrustAmount = aEntrustAmount.get(sendCarEntrust.getAddressId()).add(amount);
                    aEntrustAmount.put(sendCarEntrust.getAddressId(), entrustAmount);
                }
            }
            lOrderIds.add(sendCarEntrust.getLOrderId());
        }

        //循环单不更新物流订单委派量
        if (type == Global.NUMERICAL_TWO) {
            return lOrderIds.stream().distinct().toList();
        }

        //更新承运订单运量kwt_logistics_order_amount委派量
        for (Long lOrderId : lEntrustAmount.keySet()) {
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(lOrderId);
            BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? new BigDecimal(Global.AMOUNT) : logisticsOrder.getEntrustAmount();
            logisticsOrder.setEntrustAmount(entrustAmount.add(lEntrustAmount.get(lOrderId)));
            logisticsOrderDao.updateById(logisticsOrder);
        }

        //更新承运订单kwt_logistics_order委派量
        for (Long lAddressId : aEntrustAmount.keySet()) {
            KwtLogisticsOrderAmount logisticsOrderAmount = logisticsOrderAmountDao.findByLAddressId(lAddressId);
            BigDecimal entrustAmount = logisticsOrderAmount.getEntrustAmount() == null ? new BigDecimal(Global.AMOUNT) : logisticsOrderAmount.getEntrustAmount();
            logisticsOrderAmount.setEntrustAmount(entrustAmount.add(aEntrustAmount.get(lAddressId)));
            logisticsOrderAmountDao.updateById(logisticsOrderAmount);
        }
        return lOrderIds.stream().distinct().toList();
    }

    /**
     * @param lOrderIds 物流订单集
     * @desc 更新承运订单状态信息（包括分包上级物流订单）
     * @author zk
     * @date 2024/3/5
     **/
    public void editLogisticsOrderStatus(List<Long> lOrderIds) {
        for (Long lOrderId : lOrderIds) {
            //物流订单信息
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(lOrderId);
            //当前承运订单所属分包层级
            String pids = logisticsOrder.getPids();
            if (StringUtils.isNotBlank(pids)) {
                String[] idArray = pids.split(Global.COMMA);
                for (String id : idArray) {
                    KwtLogisticsOrder order = logisticsOrderDao.selectById(id);
                    //承运订单-待派车
                    if (order.getStatus().equals(LogisticsOrderEnum.WAIT_DELIVERY.getCode())) {
                        //更新当前承运订单状态(待派车->运输中)
                        order.setStatus(LogisticsOrderEnum.IN_TRANSIT.getCode());
                        logisticsOrderDao.updateById(order);

                        //承运订单状态记录
                        KwtLogisticsOrderTrack orderTrack = new KwtLogisticsOrderTrack();
                        orderTrack.setLOrderId(order.getId());
                        orderTrack.setStatus(order.getStatus());
                        orderTrack.setRemark(LogisticsOrderEnum.getName(order.getStatus()));
                        logisticsOrderTrackDao.insert(orderTrack);
                    }
                }
            }
        }
    }

    /**
     * @param sendCar 车辆司机信息
     * @param type    派车类型(1 趟次、2 循环)
     * @desc 运单信息
     * @author zk
     * @date 2024/3/4
     **/
    public KwtWaybillOrderV1 sendCarDriver(SendCarInfoDto sendCar, int type) {
        //车辆运单编号存储
        //String wOrderNo = getRedisGenerateWaybillOrderNo(RedisOrderGenerateEnum.WAYBILL_ORDER, OrderRuleEnum.WAYBILL_ORDER, logisticsOrder.getLOrderNo());
        //车辆信息
        RTruckVo truck = remoteFleetService.findTruck(sendCar.getTruckId());
        //司机信息
        RDriverVo driver = remoteFleetService.findDriver(sendCar.getDriverId());
        //运单信息
        KwtWaybillOrderV1 waybillOrder = new KwtWaybillOrderV1();
        waybillOrder.setEntId(LoginUserHolder.getEntId());
        waybillOrder.setWOrderNo("W" + System.currentTimeMillis());
        waybillOrder.setType(type);
        waybillOrder.setTruckId(sendCar.getTruckId());
        waybillOrder.setTruckNo(truck != null ? truck.getTruckNo() : null);
        waybillOrder.setDriverId(sendCar.getDriverId());
        waybillOrder.setDriverName(driver != null ? driver.getName() : null);
        waybillOrder.setDriverPhone(driver != null ? driver.getPhone() : null);
        waybillOrder.setDriverIdcard(driver != null ? driver.getIdcard() : null);
        waybillOrder.setStatus(CarWaybillEnum.PENDING_ORDER.getCode());
        waybillOrderV1Dao.insert(waybillOrder);
        return waybillOrder;
    }

    /**
     * @param wSubtaskId     运单-子订单ID
     * @param sendCarEntrust 运输委托信息
     * @param waybillOrder   运单信息
     * @desc 运单地址信息
     * @author zk
     * @date 2024/3/4
     **/
    public KwtWaybillOrderAddress sendCarAddress(Long wSubtaskId, SendCarEntrustDto sendCarEntrust, KwtWaybillOrderV1 waybillOrder) {
        KwtLogisticsOrderAddress logisticsOrderAddress = logisticsOrderAddressDao.selectById(sendCarEntrust.getAddressId());
        KwtWaybillOrderAddress orderAddress = new KwtWaybillOrderAddress();
        BeanUtils.copyProperties(logisticsOrderAddress, orderAddress);
        orderAddress.setId(null);
        orderAddress.setWOrderId(waybillOrder.getId());
        orderAddress.setWSubtaskId(wSubtaskId);
        orderAddress.setLAddressId(sendCarEntrust.getAddressId());
        orderAddress.setPlanTime(sendCarEntrust.getPlanTime());
        orderAddress.setEntrustAmount(BigDecimal.valueOf(sendCarEntrust.getEntrustAmount()));
        orderAddress.setSort(sendCarEntrust.getSort());
        orderAddress.setCreateBy(null);
        orderAddress.setCreateTime(null);
        orderAddress.setUpdateBy(null);
        orderAddress.setUpdateTime(null);
        waybillOrderAddressDao.insert(orderAddress);
        return orderAddress;
    }

    /**
     * @param wOrderId   车辆订单ID
     * @param wSubtaskId 车辆运单子单ID
     * @param wAddressId 车辆订单地址id
     * @param status     车辆运单状态
     * @param remark     备注
     * @desc 新增运单状态记录
     * @author zk
     * @date 2023/7/20
     **/
    public void setWaybillOrderTrack(Long wOrderId, Long wSubtaskId, Long wAddressId, Date operateTime, int status, String remark) {
        KwtWaybillOrderTrack orderTrack = new KwtWaybillOrderTrack();
        orderTrack.setWOrderId(wOrderId);
        orderTrack.setWSubtaskId(wSubtaskId);
        orderTrack.setWAddressId(wAddressId);
        orderTrack.setOperateTime(operateTime == null ? new Date() : operateTime);
        orderTrack.setStatus(status);
        orderTrack.setRemark(remark);
        waybillOrderTrackDao.insert(orderTrack);
    }

    /**
     * @param ids 车辆运单主键ID，多个已逗号隔开
     * @desc 取消派车(趟次派车)
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult cancelSendCarV1(List<Long> ids) {
        /*1、校验*/
        if (CollectionUtils.isEmpty(ids)) {
            return HttpResult.error("请选择需要撤回的运单！");
        }
        for (Long wOrderId : ids) {
            KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
            if (waybillOrder == null) {
                return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
            }
            //趟次运单才能撤回
            if (waybillOrder.getType() != Global.NUMERICAL_ONE) {
                return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "为循环运单不能撤回！");
            }
            //待接单的车辆运单才能撤回
            if (!waybillOrder.getStatus().equals(CarWaybillEnum.PENDING_ORDER.getCode())) {
                return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能撤回！");
            }

            /*2、更新运单状态*/
            waybillOrder.setStatus(CarWaybillEnum.REVOKED.getCode());
            waybillOrderV1Dao.updateById(waybillOrder);

            /*3、新增运单状态记录*/
            setWaybillOrderTrack(waybillOrder.getId(), null, null, waybillOrder.getUpdateTime(), waybillOrder.getStatus(), null);

            /*4、回退物流订单委托量*/
            /*4.1、装货址委派量entrustAmount回退*/
            //运单装货地址
            List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressDao.findByAddresses(wOrderId, AddressTypeEnum.SHIPMENT.getCode());
            for (KwtWaybillOrderAddress address : orderAddresses) {
                //物流订单-装卸货地址运量信息
                KwtLogisticsOrderAmount logisticsOrderAmount = logisticsOrderAmountDao.findByLAddressId(address.getLAddressId());
                //承运订单地址已委派量=承运订单地址原委派量-当前车辆运单地址委派量
                BigDecimal entrustAmount = logisticsOrderAmount.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderAmount.getEntrustAmount();
                logisticsOrderAmount.setEntrustAmount(entrustAmount.subtract(address.getEntrustAmount()));
                logisticsOrderAmountDao.updateById(logisticsOrderAmount);
            }

            /*4.2、物流订单委派量entrustAmount回退*/
            //运单子订单
            List<KwtWaybillOrderSubtask> orderSubtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
            for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
                //更新运单子单状态
                subtask.setStatus(waybillOrder.getStatus());
                waybillOrderSubtaskDao.updateById(subtask);

                //物流订单
                KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
                //承运订单已委派量=承运订单原委派量-当前车辆运单委派量
                BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getEntrustAmount();
                logisticsOrder.setEntrustAmount(entrustAmount.subtract(subtask.getEntrustAmount()));
                logisticsOrderDao.updateById(logisticsOrder);
            }
        }
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 确认接单
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult confirmSendCarV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //待接单的车辆运单才能确认接单
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.PENDING_ORDER.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能接单！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.PENDING_VEHICLE.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        //3、运单子单更新状态
        List<KwtWaybillOrderSubtask> orderSubtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //更新运单子单状态
            subtask.setStatus(waybillOrder.getStatus());
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*5、更新司机/车辆数据*/
        //更新司机信息
        editDriver(waybillOrder.getDriverId());
        //更新车辆信息
        editTruck(waybillOrder.getTruckId());
        //趟次运单不对物流订单委托量变更
        if (waybillOrder.getType() == Global.NUMERICAL_ONE) {
            return HttpResult.ok();
        }

        /*6、累加物流订单委托量(循环运单)*/
        /*6.1、装货址委派量entrustAmount累加*/
        //运单装货地址
        List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressDao.findByAddresses(wOrderId, AddressTypeEnum.SHIPMENT.getCode());
        for (KwtWaybillOrderAddress address : orderAddresses) {
            //物流订单-装卸货地址运量信息
            KwtLogisticsOrderAmount logisticsOrderAmount = logisticsOrderAmountDao.findByLAddressId(address.getLAddressId());
            //承运订单地址已委派量=承运订单地址原委派量+当前车辆运单地址委派量
            BigDecimal entrustAmount = logisticsOrderAmount.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderAmount.getEntrustAmount();
            logisticsOrderAmount.setEntrustAmount(entrustAmount.add(address.getEntrustAmount()));
            logisticsOrderAmountDao.updateById(logisticsOrderAmount);
        }

        /*6.2、物流订单委派量entrustAmount累加*/
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //物流订单
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            //承运订单已委派量=承运订单原委派量+当前车辆运单委派量
            BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getEntrustAmount();
            logisticsOrder.setEntrustAmount(entrustAmount.add(subtask.getEntrustAmount()));
            logisticsOrderDao.updateById(logisticsOrder);
        }
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 拒绝接单
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult refuseSendCarV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //待接单的车辆运单才能拒绝接单
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.PENDING_ORDER.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能拒绝接单！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.REJECT_ORDER.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*3、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        //4、运单子单更新状态
        List<KwtWaybillOrderSubtask> orderSubtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //更新运单子单状态
            subtask.setStatus(waybillOrder.getStatus());
            waybillOrderSubtaskDao.updateById(subtask);
        }

        //循环运单不对物流订单委托量变更
        if (waybillOrder.getType() == Global.NUMERICAL_TWO) {
            return HttpResult.ok();
        }

        /*5、回退物流订单委托量(循环运单)*/
        /*5.1、装货址委派量entrustAmount回退*/
        //运单装货地址
        List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressDao.findByAddresses(wOrderId, AddressTypeEnum.SHIPMENT.getCode());
        for (KwtWaybillOrderAddress address : orderAddresses) {
            //物流订单-装卸货地址运量信息
            KwtLogisticsOrderAmount logisticsOrderAmount = logisticsOrderAmountDao.findByLAddressId(address.getLAddressId());
            //承运订单地址已委派量=承运订单地址原委派量-+当前车辆运单地址委派量
            BigDecimal entrustAmount = logisticsOrderAmount.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderAmount.getEntrustAmount();
            logisticsOrderAmount.setEntrustAmount(entrustAmount.subtract(address.getEntrustAmount()));
            logisticsOrderAmountDao.updateById(logisticsOrderAmount);
        }

        /*5.2、物流订单委派量entrustAmount回退*/
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //物流订单
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            //承运订单已委派量=承运订单原委派量-当前车辆运单委派量
            BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getEntrustAmount();
            logisticsOrder.setEntrustAmount(entrustAmount.subtract(subtask.getEntrustAmount()));
            logisticsOrderDao.updateById(logisticsOrder);
        }

        /*6发送消息**/
        List<UserInfo> users = new ArrayList<>() {{
            add(new UserInfo(waybillOrder.getCreateBy(), waybillOrder.getEntId()));
        }};
        Map<String, Object> msgParams = new HashMap<>() {{
            put("orderNo", waybillOrder.getWOrderNo());
            put("driverName", waybillOrder.getDriverName());
        }};
        SckwMessage msg = new SckwMessage();
        msg.setRequestId(UUIDUtils.get32UUID());
        msg.setMessageEnum(MessageEnum.WAYBILL_REFUSE_SENDCAR_TRIP);
        msg.setParams(msgParams);
        msg.setMsgUrls(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
            put("app", refuseSendCarAppUrl);
            put("pc", refuseSendCarPcUrl);
        }});
        msg.setUserInfos(users);
        msg.setCreateBy(LoginUserHolder.getUserId());
        streamBridge.send("sckw-message", JSON.toJSONString(msg));
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 确认出车
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult confirmDepartureV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //待出车的车辆运单才能出车
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.PENDING_VEHICLE.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态不能出车！");
        }
        //车辆任务中校验
        WaybillCountVo countVo = waybillOrderV1Dao.findCountByDriverOrTruck(null, waybillOrder.getTruckId());
        if (countVo.getTotalExecute() > 0) {
            return HttpResult.error("车辆" + waybillOrder.getTruckNo() + "正在任务中，暂不能出车！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.EXIT_COMPLETED.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        //3、运单子单更新状态
        List<KwtWaybillOrderSubtask> orderSubtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //更新运单子单状态
            subtask.setStatus(waybillOrder.getStatus());
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*5、更新司机/车辆数据*/
        //更新司机信息
        editDriver(waybillOrder.getDriverId());
        //更新车辆信息
        editTruck(waybillOrder.getTruckId());
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 拒绝出车
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult refuseDepartureV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //待出车的车辆运单才能拒绝出车
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.PENDING_VEHICLE.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态不能拒绝出车！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.REFUSE_TRAFFIC.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        //3、运单子单更新状态
        List<KwtWaybillOrderSubtask> orderSubtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //更新运单子单状态
            subtask.setStatus(waybillOrder.getStatus());
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*5、回退物流订单委托量*/
        /*5.1、装货址委派量entrustAmount回退*/
        //运单装货地址
        List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressDao.findByAddresses(wOrderId, AddressTypeEnum.SHIPMENT.getCode());
        for (KwtWaybillOrderAddress address : orderAddresses) {
            //物流订单-装卸货地址运量信息
            KwtLogisticsOrderAmount logisticsOrderAmount = logisticsOrderAmountDao.findByLAddressId(address.getLAddressId());
            //承运订单地址已委派量=承运订单地址原委派量-当前车辆运单地址委派量
            BigDecimal entrustAmount = logisticsOrderAmount.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrderAmount.getEntrustAmount();
            logisticsOrderAmount.setEntrustAmount(entrustAmount.subtract(address.getEntrustAmount()));
            logisticsOrderAmountDao.updateById(logisticsOrderAmount);
        }

        /*5.2、物流订单委派量entrustAmount回退*/
        for (KwtWaybillOrderSubtask subtask : orderSubtasks) {
            //物流订单
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            //承运订单已委派量=承运订单原委派量-当前车辆运单委派量
            BigDecimal entrustAmount = logisticsOrder.getEntrustAmount() == null ? NumberConstant.ZERO_TWO : logisticsOrder.getEntrustAmount();
            logisticsOrder.setEntrustAmount(entrustAmount.subtract(subtask.getEntrustAmount()));
            logisticsOrderDao.updateById(logisticsOrder);
        }

        /*6、发送消息**/
        List<UserInfo> users = new ArrayList<>() {{
            add(new UserInfo(waybillOrder.getCreateBy(), waybillOrder.getEntId()));
        }};
        Map<String, Object> msgParams = new HashMap<>() {{
            put("orderNo", waybillOrder.getWOrderNo());
            put("driverName", waybillOrder.getDriverName());
        }};
        SckwMessage msg = new SckwMessage();
        msg.setRequestId(UUIDUtils.get32UUID());
        msg.setMessageEnum(MessageEnum.WAYBIL_CONFIRM_DEPARTURE);
        msg.setParams(msgParams);
        msg.setMsgUrls(new HashMap<>(Global.NUMERICAL_SIXTEEN) {{
            put("app", refuseSendCarAppUrl);
            put("pc", refuseSendCarPcUrl);
        }});
        msg.setUserInfos(users);
        msg.setCreateBy(LoginUserHolder.getUserId());
        streamBridge.send("sckw-message", JSON.toJSONString(msg));
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 到达装货地点
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult arriveLoadLocationV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //已出车、到达装货地、已装货、到达卸货地、已卸货的车辆运单才能到达装货地点
        if (!CarWaybillEnum.arriveLocation(waybillOrder.getStatus())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能到达装货地点！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.WAIT_LOADING.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*3、更新车辆运单-子单*/
        //运单子单信息
        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(params.getWSubtaskId());
        orderSubtask.setStatus(waybillOrder.getStatus());
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 装货-多单位+多地址
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult loadingV1(WaybillOrderTicketV4Dto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //到达装货地的车辆运单才能装货
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.WAIT_LOADING.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能装货！");
        }

        /*2、更新车辆运单*/
        /*2.1、更新车辆运单-状态*/
        waybillOrder.setStatus(CarWaybillEnum.COMPLETION_LOADING.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*2.2、更新车辆运单-子单*/
        //运单子单信息
        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(params.getWSubtaskId());
        //榜单信息
        List<WaybillOrderTicketLoadingDto> loading = params.getLoading();
        BigDecimal loadAmout = waybillOrderTicketService.countAmount(loading, orderSubtask.getUnit(), orderSubtask.getLoadAmount());
        orderSubtask.setLoadAmount(orderSubtask.getLoadAmount().add(loadAmout));
        orderSubtask.setStatus(waybillOrder.getStatus());
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*3、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*4、新增装卸货榜单信息*/
        waybillOrderTicketService.addTicketV1(loading, waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getUrls(), params.getOperateTime(), Global.NUMERICAL_ONE);
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 到达卸货地点
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult arriveUnloadLocationV1(OperateWaybillDto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //已出车、到达装货地、已装货、到达卸货地、已卸货的车辆运单才能到达卸货地点
        if (!CarWaybillEnum.arriveLocation(waybillOrder.getStatus())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能到达卸货地点！");
        }

        /*2、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.WAIT_UNLOADING.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*3、更新车辆运单-子单*/
        //运单子单信息
        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(params.getWSubtaskId());
        orderSubtask.setStatus(waybillOrder.getStatus());
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 卸货-多单位
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult unloadingV1(WaybillOrderTicketV4Dto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //到达卸货地的车辆运单才能卸货
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.WAIT_UNLOADING.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能卸货！");
        }

        /*2、更新车辆运单*/
        /*2.1、更新车辆运单-状态*/
        waybillOrder.setStatus(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*2.2、更新车辆运单-子单*/
        //运单子单信息
        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(params.getWSubtaskId());
        //物流运单信息
        KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(orderSubtask.getLOrderId());
        //榜单信息
        List<WaybillOrderTicketLoadingDto> loading = params.getLoading();
        BigDecimal unloadAmout = waybillOrderTicketService.countAmount(loading, orderSubtask.getUnit(), orderSubtask.getLoadAmount());
        orderSubtask.setUnloadAmount(orderSubtask.getUnloadAmount().add(unloadAmout));
        orderSubtask.setDeficitAmount(orderSubtask.getLoadAmount().subtract(orderSubtask.getUnloadAmount()));
        BigDecimal deficitPrice = deficitPrice(orderSubtask.getLoadAmount(), orderSubtask.getDeficitAmount(),
                logisticsOrder.getLoss(), logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice());
        orderSubtask.setDeficitPrice(deficitPrice);
        orderSubtask.setStatus(waybillOrder.getStatus());
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*3、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*4、新增装卸货榜单信息*/
        waybillOrderTicketService.addTicketV1(loading, waybillOrder.getId(), params.getWSubtaskId(), params.getWAddressId(), params.getUrls(), params.getOperateTime(), Global.NUMERICAL_TWO);

        /*5、校验运单-子单是否全部运输完毕*/
        //运单地址信息
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findBySubtaskId(params.getWSubtaskId(), null);
        //运单地址榜单信息
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, params.getWSubtaskId(), null, orderSubtask.getUnit());
        ;
        //运单子单是否已经运输完成
        if (addresses.size() != tickets.size()) {
            return HttpResult.ok();
        }

        //更新运单-子单状态
        orderSubtask.setStatus(CarWaybillEnum.APPROVAL_TREAT.getCode());
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*6、校验运单是否全部运输完毕*/
        //校验子单是否全部为待审批
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            if (!subtask.getStatus().equals(CarWaybillEnum.APPROVAL_TREAT.getCode())) {
                return HttpResult.ok();
            }
        }

        /*6.1、更新运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.APPROVAL_TREAT.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*6.2、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, params.getOperateTime(), waybillOrder.getStatus(), params.getRemark());

        /*7、更新司机/车辆数据*/
        //更新司机信息
        editDriver(waybillOrder.getDriverId());
        //更新车辆信息
        editTruck(waybillOrder.getTruckId());

        /*8、循环单全部装卸货完重新生成运单*/
        if (waybillOrder.getType() == Global.NUMERICAL_TWO) {
            recreateWaybillOrder(waybillOrder);
        }
        return HttpResult.ok();
    }

    /**
     * @param waybillOrder {}
     * @desc 重新生成运单
     * @author zk
     * @date 2024/3/7
     **/
    public void recreateWaybillOrder(KwtWaybillOrderV1 waybillOrder) {
        //运单信息kwt_waybill_order
        KwtWaybillOrderV1 waybillOrderNew = new KwtWaybillOrderV1();
        BeanUtils.copyProperties(waybillOrder, waybillOrderNew);
        waybillOrderNew.setId(null);
        waybillOrderNew.setWOrderNo("W" + System.currentTimeMillis());
        waybillOrderNew.setStatus(CarWaybillEnum.PENDING_ORDER.getCode());
        waybillOrderNew.setCreateTime(null);
        waybillOrderNew.setUpdateTime(null);
        waybillOrderV1Dao.insert(waybillOrderNew);

        //运单子单信息kwt_waybill_order_subtask
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(waybillOrder.getId());
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            KwtWaybillOrderSubtask subtaskNew = new KwtWaybillOrderSubtask();
            BeanUtils.copyProperties(subtask, subtaskNew);
            subtaskNew.setId(null);
            subtaskNew.setWOrderId(waybillOrderNew.getId());
            subtaskNew.setWOrderNo(waybillOrderNew.getWOrderNo());
            subtaskNew.setLoadAmount(NumberConstant.ZERO_TWO);
            subtaskNew.setUnloadAmount(NumberConstant.ZERO_TWO);
            subtaskNew.setDeficitAmount(NumberConstant.ZERO_TWO);
            subtaskNew.setDeficitPrice(NumberConstant.ZERO_TWO);
            subtaskNew.setStatus(waybillOrderNew.getStatus());
            subtaskNew.setCreateTime(null);
            subtaskNew.setUpdateTime(null);
            waybillOrderSubtaskDao.insert(subtaskNew);

            //运单地址信息kwt_waybill_order_address
            List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findBySubtaskId(subtask.getId(), null);
            for (KwtWaybillOrderAddress address : addresses) {
                KwtWaybillOrderAddress addressNew = new KwtWaybillOrderAddress();
                BeanUtils.copyProperties(address, addressNew);
                addressNew.setId(null);
                addressNew.setWOrderId(waybillOrderNew.getId());
                addressNew.setWSubtaskId(subtaskNew.getId());
                addressNew.setCreateTime(null);
                addressNew.setUpdateTime(null);
                waybillOrderAddressDao.insert(addressNew);
            }
        }

        //新增运单状态记录kwt_waybill_order_track
        setWaybillOrderTrack(waybillOrderNew.getId(), null, null, waybillOrderNew.getCreateTime(), waybillOrderNew.getStatus(), null);
    }

    /**
     * @param params {}
     * @desc 修改单证
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult editTicketV1(WaybillOrderEditTicketDto params) {
        /*1、校验*/
        Long wTicketId = params.getWTicketId();
        KwtWaybillOrderTicket ticket = waybillOrderTicketDao.selectById(wTicketId);
        //榜单信息
        if (ticket == null) {
            return HttpResult.error("榜单信息不存在，请确认！");
        }
        Long wOrderId = ticket.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //已出车、到达装货地、已装货、到达卸货地、已卸货的车辆运单才能卸货
        if (!CarWaybillEnum.arriveLoading(waybillOrder.getStatus())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能修改榜单！");
        }
        //地址信息
        KwtWaybillOrderAddress address = waybillOrderAddressDao.selectById(ticket.getWAddressId());
        if (address == null) {
            return HttpResult.error("运单该地址已不存在！");
        }

        /*2、更新装卸货榜单信息*/
        //榜单信息
        List<WaybillOrderTicketLoadingDto> loading = params.getLoading();
        waybillOrderTicketService.editTicketV1(loading, ticket.getWAddressId(), params.getUrls(), params.getOperateTime());

        /*3、更新车辆运单-子单*/
        //运单子单信息
        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(ticket.getWSubtaskId());
        //物流运单信息
        KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(orderSubtask.getLOrderId());
        //运单-子单装货榜单信息
        List<KwtWaybillOrderTicket> loadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.SHIPMENT.getCode(), orderSubtask.getUnit());
        //运单-子单卸货榜单信息
        List<KwtWaybillOrderTicket> unloadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.TAKE.getCode(), orderSubtask.getUnit());
        //装货-总量
        BigDecimal loadAmount = loadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        //卸货-总量
        BigDecimal unloadAmount = unloadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        orderSubtask.setLoadAmount(loadAmount);
        orderSubtask.setUnloadAmount(unloadAmount);
        orderSubtask.setDeficitAmount(orderSubtask.getLoadAmount().subtract(orderSubtask.getUnloadAmount()));
        BigDecimal deficitPrice = deficitPrice(orderSubtask.getLoadAmount(), orderSubtask.getDeficitAmount(),
                logisticsOrder.getLoss(), logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice());
        orderSubtask.setDeficitPrice(deficitPrice);
        waybillOrderSubtaskDao.updateById(orderSubtask);

        /*4、更新车辆运单子单状态*/
        //运单子单信息
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(orderSubtask.getWOrderId());
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            //运单子单状态不为驳回状态则不更新运单状态
            if (!subtask.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
                return HttpResult.ok();
            }
            //榜单存在审核失败状态则不更新运单状态
            List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(null, subtask.getId(), null);
            for (KwtWaybillOrderTicket ticket1 : tickets) {
                if (ticket1.getStatus() == Global.NUMERICAL_ONE) {
                    return HttpResult.ok();
                }
            }
            //运单-子弹当前为驳回则状态更新为单证更新审核中
            int status = orderSubtask.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode()) ? CarWaybillEnum.APPROVAL_IN.getCode() : orderSubtask.getStatus();
            subtask.setStatus(status);
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*5、更新车辆运单-状态*/
        //运单状态不为驳回状态则不更新运单状态
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
            return HttpResult.ok();
        }
        //运单子单存在非待审核和审核中则不更新
        subtasks = waybillOrderSubtaskDao.findByWOrderId(orderSubtask.getWOrderId());
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            if (!subtask.getStatus().equals(CarWaybillEnum.APPROVAL_IN.getCode())
                    && !subtask.getStatus().equals(CarWaybillEnum.APPROVAL_TREAT.getCode())) {
                return HttpResult.ok();
            }
        }
        waybillOrder.setStatus(CarWaybillEnum.APPROVAL_IN.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*4.2、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, null, waybillOrder.getStatus(), null);
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 修改单证-多个修改
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult editTicketV2(List<WaybillOrderEditTicketDto> params) {
        /*1、校验*/
        for (WaybillOrderEditTicketDto ticketDto : params) {
            Long wTicketId = ticketDto.getWTicketId();
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.selectById(wTicketId);
            //榜单信息
            if (ticket == null) {
                return HttpResult.error("榜单信息不存在，请确认！");
            }
        }

        //数据处理-榜单
        Long wOrderId = null;
        //运单信息
        KwtWaybillOrderV1 waybillOrder = null;
        for (WaybillOrderEditTicketDto ticketDto : params) {
            Long wTicketId = ticketDto.getWTicketId();
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.selectById(wTicketId);
            wOrderId = ticket.getWOrderId();
            //运单信息
            waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
            if (waybillOrder == null) {
                return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
            }
            //已出车、到达装货地、已装货、到达卸货地、已卸货的车辆运单才能卸货
            if (!CarWaybillEnum.editTicket(waybillOrder.getStatus())) {
                return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能修改榜单！");
            }
            //地址信息
            KwtWaybillOrderAddress address = waybillOrderAddressDao.selectById(ticket.getWAddressId());
            if (address == null) {
                return HttpResult.error("运单该地址已不存在！");
            }

            /*2、更新装卸货榜单信息*/
            //榜单信息
            List<WaybillOrderTicketLoadingDto> loading = ticketDto.getLoading();
            waybillOrderTicketService.editTicketV1(loading, ticket.getWAddressId(), ticketDto.getUrls(), ticketDto.getOperateTime());

            /*3、更新车辆运单-子单*/
            //运单子单信息
            KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(ticket.getWSubtaskId());

            //物流运单信息
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(orderSubtask.getLOrderId());
            //运单-子单装货榜单信息
            List<KwtWaybillOrderTicket> loadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.SHIPMENT.getCode(), orderSubtask.getUnit());
            //运单-子单卸货榜单信息
            List<KwtWaybillOrderTicket> unloadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.TAKE.getCode(), orderSubtask.getUnit());
            //装货-总量
            BigDecimal loadAmount = loadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //卸货-总量
            BigDecimal unloadAmount = unloadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            orderSubtask.setLoadAmount(loadAmount);
            orderSubtask.setUnloadAmount(unloadAmount);
            orderSubtask.setDeficitAmount(orderSubtask.getLoadAmount().subtract(orderSubtask.getUnloadAmount()));
            BigDecimal deficitPrice = deficitPrice(orderSubtask.getLoadAmount(), orderSubtask.getDeficitAmount(),
                    logisticsOrder.getLoss(), logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice());
            orderSubtask.setDeficitPrice(deficitPrice);
            waybillOrderSubtaskDao.updateById(orderSubtask);
        }

        /*4、更新车辆运单子单状态*/
        //运单子单信息
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            //运单子单状态不为驳回状态则不更新运单状态
            if (!subtask.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
                return HttpResult.ok();
            }
            //榜单存在审核失败状态则不更新运单状态
            List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(null, subtask.getId(), null);
            for (KwtWaybillOrderTicket ticket1 : tickets) {
                if (ticket1.getStatus() == Global.NUMERICAL_ONE) {
                    return HttpResult.ok();
                }
            }
            //运单-子单当前为驳回则状态更新为单证更新审核中
            int status = subtask.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode()) ? CarWaybillEnum.APPROVAL_IN.getCode() : subtask.getStatus();
            subtask.setStatus(status);
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*5、更新车辆运单-状态*/
        //运单状态不为驳回状态则不更新运单状态
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
            return HttpResult.ok();
        }
        //运单子单存在非待审核和审核中则不更新
        subtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            if (!subtask.getStatus().equals(CarWaybillEnum.APPROVAL_IN.getCode())
                    && !subtask.getStatus().equals(CarWaybillEnum.APPROVAL_TREAT.getCode())) {
                return HttpResult.ok();
            }
        }
        waybillOrder.setStatus(CarWaybillEnum.APPROVAL_IN.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*4.2、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, null, waybillOrder.getStatus(), null);
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 单证审核-驳回
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult approvalReject(List<WaybillOrderTicketApprovalRejectDto> params) {
        /*1、验证*/
        if (CollectionUtils.isEmpty(params)) {
            return HttpResult.error("请选择需要驳回的榜单！");
        }
        //运单ID集
        List<Long> wOrderIds = new ArrayList<>();
        //运单-子单ID集
        List<Long> wSubtaskIds = new ArrayList<>();
        for (WaybillOrderTicketApprovalRejectDto approval : params) {
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.selectById(approval.getWTicketId());
            if (ticket == null) {
                return HttpResult.error("榜单不存在请确认！");
            }
            wOrderIds.add(ticket.getWOrderId());
            wSubtaskIds.add(ticket.getWSubtaskId());
        }

        /*2、数据处理*/
        /*2.1、修改榜单状态*/
        for (WaybillOrderTicketApprovalRejectDto approval : params) {
            KwtWaybillOrderTicket ticket = waybillOrderTicketDao.selectById(approval.getWTicketId());
            ticket.setStatus(Global.NUMERICAL_ONE);
            ticket.setRemark(approval.getRemark());
            waybillOrderTicketDao.updateById(ticket);
        }
        /*2.2、修改运单状态*/
        for (Long wOrderId : wOrderIds) {
            KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
            if (waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
                continue;
            }
            waybillOrder.setStatus(CarWaybillEnum.APPROVAL_NO_PASS.getCode());
            waybillOrderV1Dao.updateById(waybillOrder);

            /*2.3、新增运单状态记录*/
            setWaybillOrderTrack(waybillOrder.getId(), null, null, null, waybillOrder.getStatus(), null);
        }

        /*2.4、修改运单-子单状态*/
        for (Long wSubtaskId : wSubtaskIds) {
            KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(wSubtaskId);
            if (orderSubtask.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())) {
                continue;
            }
            orderSubtask.setStatus(CarWaybillEnum.APPROVAL_NO_PASS.getCode());
            waybillOrderSubtaskDao.updateById(orderSubtask);
        }
        return HttpResult.ok();
    }

    /**
     * @param params {}
     * @desc 单证审核（编辑单证）
     * @author zk
     * @date 2024/3/7
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult approvalEditTicketV1(WaybillOrderTicketApprovalV2Dto params) {
        /*1、校验*/
        Long wOrderId = params.getWOrderId();
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("运单" + wOrderId + "不存在，请确认！");
        }
        //已出车、到达装货地、已装货、到达卸货地、已卸货的车辆运单才能卸货
        if (!waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_TREAT.getCode())
                && waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_NO_PASS.getCode())
                && waybillOrder.getStatus().equals(CarWaybillEnum.APPROVAL_IN.getCode())) {
            return HttpResult.error("运单" + waybillOrder.getWOrderNo() + "当前状态已不能审核！");
        }
        //变更榜单信息校验
        if (CollectionUtils.isNotEmpty(params.getTickets())) {
            //变更榜单信息
            List<WaybillOrderTicketV4Dto> tickets = params.getTickets();
            for (WaybillOrderTicketV4Dto ticket : tickets) {
                //地址信息
                KwtWaybillOrderAddress address = waybillOrderAddressDao.selectById(ticket.getWAddressId());
                if (address == null) {
                    return HttpResult.error("运单该地址已不存在！");
                }
            }
        }

        /*2、更新榜单信息*/
        /*2.1、同步更新变更榜单信息*/
        editTicket(params);

        /*2.2、更新榜单状态为审核通过*/
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(wOrderId, null, null);
        for (KwtWaybillOrderTicket ticket : tickets) {
            ticket.setStatus(Global.NUMERICAL_TWO);
            waybillOrderTicketDao.updateById(ticket);
        }

        /*3、修改运单状态*/
        waybillOrder.setStatus(CarWaybillEnum.APPROVAL_PASS.getCode());
        waybillOrderV1Dao.updateById(waybillOrder);

        /*4、新增运单状态记录*/
        setWaybillOrderTrack(waybillOrder.getId(), null, null, null, waybillOrder.getStatus(), null);

        /*5、修改运单-子单状态*/
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskDao.findByWOrderId(wOrderId);
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            subtask.setStatus(waybillOrder.getStatus());
            waybillOrderSubtaskDao.updateById(subtask);
        }

        /*6、更新司机/车辆数据*/
        //更新司机信息
        editDriver(waybillOrder.getDriverId());
        //更新车辆信息
        editTruck(waybillOrder.getTruckId());

        /*7、物流订单信息更新*/
        editLogisticsOrder(subtasks);
        //8.运单常用线路保持
        //8.1根据订单号获取地址信息
        editTruckRoute(params, waybillOrder, wOrderId);
        return HttpResult.ok();
    }

    private void editTruckRoute(WaybillOrderTicketApprovalV2Dto params, KwtWaybillOrderV1 waybillOrder, Long wOrderId) {
        try {
            List<KwtWaybillOrderAddress> addressList = waybillOrderAddressRepository.queryByWOrderId(params.getWOrderId());
            if (CollectionUtils.isNotEmpty(addressList)){
                Set<Long> addressIds = addressList.stream()
                        .map(KwtWaybillOrderAddress::getId)
                        .collect(Collectors.toSet());
                //运单id和地址类型组装key映射地址对象
                Map<String, KwtWaybillOrderAddress> keyAndAddressMap = addressList.stream()
                        .peek(a -> a.setWOrderIdAddressTypeKey(a.getWOrderId() + CommonConstants.UNDERSCORE + a.getAddressType()))
                        .collect(Collectors.toMap(KwtWaybillOrderAddress::getWOrderIdAddressTypeKey, Function.identity(), (k1, k2) -> k1));
                //查询运单状态信息
                //List<KwtWaybillOrderTrack> tracks =  kwtWaybillOrderTrackRepository.queryByAddressIds(addressIds);
                List<KwtWaybillOrderTicket> tracks = kwtWaybillOrderTicketRepository.queryByAddressIds(addressIds);
                //地址id映射运单状态
                Map<Long, KwtWaybillOrderTicket> addressIdAndTrackMap = tracks.stream()
                        .collect(Collectors.toMap(KwtWaybillOrderTicket::getWAddressId, Function.identity(), (k1, k2) -> k1));
                RTruckRouteVo rTruckRouteVo = new RTruckRouteVo();
                rTruckRouteVo.setTruckId(waybillOrder.getTruckId());
                rTruckRouteVo.setTruckNo(waybillOrder.getTruckNo());
                rTruckRouteVo.setDriverId(waybillOrder.getDriverId());
                rTruckRouteVo.setEntId(waybillOrder.getEntId());
                KwtWaybillOrderAddress startPoint = keyAndAddressMap.getOrDefault(wOrderId + CommonConstants.UNDERSCORE + AddressTypeEnum.SHIPMENT.getCode(), new KwtWaybillOrderAddress());
                rTruckRouteVo.setStartPoint(startPoint.getDetailAddress());
                KwtWaybillOrderAddress unloadingPoint = keyAndAddressMap.getOrDefault(wOrderId + CommonConstants.UNDERSCORE + AddressTypeEnum.TAKE.getCode(), new KwtWaybillOrderAddress());
                rTruckRouteVo.setUnloadingPoint(unloadingPoint.getDetailAddress());
                AtomicReference<Date> startTime = new AtomicReference<>();
                AtomicReference<Date> unloadingTime = new AtomicReference<>();
                addressList.forEach(a->{
                    KwtWaybillOrderTicket kwtWaybillOrderTrack = addressIdAndTrackMap.get(a.getId());
                    if (Objects.equals(a.getAddressType(), AddressTypeEnum.SHIPMENT.getCode())){
                        startTime.set(kwtWaybillOrderTrack.getOperateTime());
                    }
                    if (Objects.equals(a.getAddressType(), AddressTypeEnum.TAKE.getCode())){
                        unloadingTime.set(kwtWaybillOrderTrack.getOperateTime());
                    }
                });
                Long shortestTime = DateUtil.getDifferenceInMillis(unloadingTime.get(), startTime.get());
                rTruckRouteVo.setShortestTime(Objects.isNull(shortestTime) ? null: String.valueOf(shortestTime));

                //从中台查询轨迹信息
                VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                vehicleDataDTO.setWOrderNo(waybillOrder.getWOrderNo());

                try {
                    // 使用 Feign 调用查询车辆轨迹列表
                    com.sckw.transport.api.model.dto.VehicleDataDTO vehicleDataDTO1 = new com.sckw.transport.api.model.dto.VehicleDataDTO();
                    vehicleDataDTO.setWOrderNo(waybillOrder.getWOrderNo());
                    BaseIotResult<List<com.sckw.transport.api.model.dto.VehicleReturnData>> result = vehicleTraceClient.queryVehicleDataList(vehicleDataDTO1);

                    if (result != null && org.apache.commons.lang3.StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
                        List<com.sckw.transport.api.model.dto.VehicleReturnData> vehicleReturn = result.getData();
                        List<VehicleRouteData> vehicleReturnData = vehicleReturn.stream().map(x->{
                            VehicleRouteData vehicleRouteData = new VehicleRouteData();
                            vehicleRouteData.setTs(Objects.nonNull(x.getTs()) ? x.getTs().toLocalDateTime() : null);
                            vehicleRouteData.setLongitude(x.getLongitude());
                            vehicleRouteData.setLatitude(x.getLatitude());
                            return vehicleRouteData;
                        }).collect(Collectors.toList());
                        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(vehicleReturnData)) {
                            rTruckRouteVo.setPointInfo(com.alibaba.fastjson.JSON.toJSONString(vehicleReturnData));
                        }
                    } else {
                        log.warn("查询车辆轨迹返回空数据, 运单号: {}", waybillOrder.getWOrderNo());
                    }
                } catch (Exception e) {
                    log.error("查询任务轨迹异常, 运单号: {}", waybillOrder.getWOrderNo(), e);
                }

                remoteFleetService.saveOrUpdate(rTruckRouteVo);
            }
        } catch (Exception e) {
            log.error("修改惯用线路异常:",e);
        }
    }

    /**
     * @param params {}
     * @desc 更新榜单信息-单证审核
     * @author zk
     * @date 2024/3/7
     **/
    public void editTicket(WaybillOrderTicketApprovalV2Dto params) {
        //变更榜单信息
        List<WaybillOrderTicketV4Dto> tickets = params.getTickets();
        if (CollectionUtils.isEmpty(tickets)) {
            return;
        }

        for (WaybillOrderTicketV4Dto ticket : tickets) {
            //车辆运单ID
            Long wOrderId = ticket.getWOrderId();

            /*1、更新装卸货榜单信息*/
            //榜单信息
            List<WaybillOrderTicketLoadingDto> loading = ticket.getLoading();
            waybillOrderTicketService.editTicketV1(loading, ticket.getWAddressId(), ticket.getUrls(), ticket.getOperateTime());

            /*2、更新车辆运单-子单*/
            //运单子单信息
            KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskDao.selectById(ticket.getWSubtaskId());
            //物流运单信息
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(orderSubtask.getLOrderId());
            //运单-子单装货榜单信息
            List<KwtWaybillOrderTicket> loadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.SHIPMENT.getCode(), orderSubtask.getUnit());
            //运单-子单卸货榜单信息
            List<KwtWaybillOrderTicket> unloadTickets = waybillOrderTicketDao.findWaybillOrderTicketV1(wOrderId, ticket.getWSubtaskId(), AddressTypeEnum.TAKE.getCode(), orderSubtask.getUnit());
            //装货-总量
            BigDecimal loadAmount = loadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //卸货-总量
            BigDecimal unloadAmount = unloadTickets.stream().map(KwtWaybillOrderTicket::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            orderSubtask.setLoadAmount(loadAmount);
            orderSubtask.setUnloadAmount(unloadAmount);
            orderSubtask.setDeficitAmount(orderSubtask.getLoadAmount().subtract(orderSubtask.getUnloadAmount()));
            BigDecimal deficitPrice = deficitPrice(orderSubtask.getLoadAmount(), orderSubtask.getDeficitAmount(),
                    logisticsOrder.getLoss(), logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice());
            orderSubtask.setDeficitPrice(deficitPrice);
            waybillOrderSubtaskDao.updateById(orderSubtask);
        }
    }

    /**
     * @param subtasks {}
     * @desc 更新物流订单信息-单证审核
     * @author zk
     * @date 2024/3/7
     **/
    public void editLogisticsOrder(List<KwtWaybillOrderSubtask> subtasks) {
        //数据处理
        for (KwtWaybillOrderSubtask subtask : subtasks) {
            /*1、物流订单信息更新*/
            //物流订单信息
            KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(subtask.getLOrderId());
            //装货统计
            Map<String, Object> queryParams = new HashMap<>(NumberConstant.SIXTEEN);
            queryParams.put("lOrderId", subtask.getLOrderId());
            queryParams.put("unit", logisticsOrder.getUnit());
            queryParams.put("type", NumberConstant.ONE);
            queryParams.put("passStatus", Global.NUMERICAL_ONE);
            WaybillCountVo loadCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);
            //卸货统计
            queryParams.put("type", NumberConstant.TWO);
            WaybillCountVo unloadCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);

            //委派量多退少补entrustAmount(委派未运量=运单子单承运委派量-运单子单装货量)
            BigDecimal residue = subtask.getEntrustAmount().subtract(subtask.getLoadAmount());
            logisticsOrder.setEntrustAmount(logisticsOrder.getEntrustAmount().subtract(residue));
            logisticsOrder.setLoadAmount(loadCount.getAmount());
            logisticsOrder.setLoadTime(loadCount.getLoadTime());
            logisticsOrder.setUnloadAmount(unloadCount.getAmount());
            logisticsOrder.setUnloadTime(unloadCount.getUnloadTime());
            logisticsOrder.setDeficitAmount(logisticsOrder.getLoadAmount().subtract(logisticsOrder.getUnloadAmount()));
            BigDecimal deficitPrice = deficitPrice(logisticsOrder.getLoadAmount(), logisticsOrder.getDeficitAmount(),
                    logisticsOrder.getLoss(), logisticsOrder.getLossUnit(), logisticsOrder.getGoodsPrice());
            logisticsOrder.setDeficitPrice(deficitPrice);
            logisticsOrder.setTotalTake(logisticsOrder.getTotalTake() == null ? NumberConstant.ONE : logisticsOrder.getTotalTake() + NumberConstant.ONE);
            logisticsOrderDao.updateById(logisticsOrder);

            /*2、物流订单地址运量信息更新*/
            List<KwtLogisticsOrderAmount> amounts = logisticsOrderAmountDao.findByLOrderId(subtask.getLOrderId());
            for (KwtLogisticsOrderAmount amount : amounts) {
                //物流运单地址信息
                KwtLogisticsOrderAddress address = logisticsOrderAddressDao.selectById(amount.getLAddressId());
                //运单地址进行统计
                queryParams.clear();
                queryParams.put("unit", logisticsOrder.getUnit());
                queryParams.put("lAddressId", amount.getLAddressId());
                queryParams.put("passStatus", Global.NUMERICAL_ONE);
                WaybillCountVo waybillCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);
                if (address.getAddressType().equals(AddressTypeEnum.SHIPMENT.getCode())) {
                    //计算单个地址需要回退委派量
                    BigDecimal countEntrustAmount = countEntrustAmount(subtask, amount.getLAddressId());
                    amount.setEntrustAmount(amount.getEntrustAmount().subtract(countEntrustAmount));
                    amount.setLoadAmount(waybillCount.getAmount());
                    amount.setLoadTime(waybillCount.getLoadTime() != null ? LocalDateTime.ofInstant(waybillCount.getLoadTime().toInstant(), ZoneId.systemDefault()) : null);
                } else {
                    amount.setUnloadAmount(waybillCount.getAmount());
                    amount.setUnloadTime(waybillCount.getUnloadTime() != null ? LocalDateTime.ofInstant(waybillCount.getUnloadTime().toInstant(), ZoneId.systemDefault()) : null);
                }
                logisticsOrderAmountDao.updateById(amount);
            }

            /*3、物流订单辅助单位信息更新*/
            kwtLogisticsOrderGoodsService.editLogisticsOrderGoodsLoading(logisticsOrder.getId());

            /*4、校验当前承运订单是否运输完成(修改状态+统计量)*/
            editLogisticsTotalCount(logisticsOrder.getId());
        }
    }

    /**
     * @param subtask {}
     * @desc 计算单个地址需要回退委派量-单证审核
     * @author zk
     * @date 2024/3/7
     **/
    public BigDecimal countEntrustAmount(KwtWaybillOrderSubtask subtask, Long lAddressId) {
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByLAddressIds(subtask.getWOrderId(), new ArrayList<>(){{add(lAddressId);}});
        //运单地址进行统计
        Map<String, Object> queryParams = new HashMap<>(NumberConstant.SIXTEEN);
        queryParams.put("wOrderId", subtask.getWOrderId());
        queryParams.put("lAddressId", lAddressId);
        queryParams.put("passStatus", Global.NUMERICAL_ONE);
        queryParams.put("unit", subtask.getUnit());
        WaybillCountVo waybillCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);
        //地址总委派量
        BigDecimal entrustAmount = addresses.stream().map(KwtWaybillOrderAddress::getEntrustAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        //委派量多退少补entrustAmount(委派未运量=运单子单承运委派量-运单子单装货量)
        return entrustAmount.subtract(waybillCount.getAmount());
    }

    /**
     * @param lOrderId 承运订单ID
     * @desc 校验当前承运订单是否运输完成(修改状态 + 统计量)
     * @author zk
     * @date 2024/3/8
     **/
    public void editLogisticsTotalCount(Long lOrderId) {
        /*1、物流订单信息更新*/
        //物流订单信息
        KwtLogisticsOrder logisticsOrder = logisticsOrderDao.selectById(lOrderId);
        //装货统计(当前物流订单)
        Map<String, Object> queryParams = new HashMap<>(NumberConstant.SIXTEEN);
        queryParams.put("lOrderId", lOrderId);
        queryParams.put("unit", logisticsOrder.getUnit());
        queryParams.put("type", NumberConstant.ONE);
        queryParams.put("passStatus", Global.NUMERICAL_ONE);
        WaybillCountVo loadCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);
        //卸货统计(当前物流订单)
        queryParams.put("type", NumberConstant.TWO);
        WaybillCountVo unloadCount = waybillOrderV1Dao.findTicketCountByAddress(queryParams);

        //下级物流订单统计
        Map<String, Object> params = new HashMap<>(){{put("upperlOrderId", lOrderId); put("ownOrderId", lOrderId);}};
        List<KwtLogisticsOrder> logisticsOrders = logisticsOrderDao.findLogisticsOrder(params);
        BigDecimal totalLoadAmount = logisticsOrders.stream().map(KwtLogisticsOrder::getTotalLoadAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalUnloadAmount = logisticsOrders.stream().map(KwtLogisticsOrder::getTotalUnloadAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        int sum = logisticsOrders.stream().mapToInt(KwtLogisticsOrder::getTotalTake).sum();
        int totalTake = waybillOrderV1Dao.findWaybillOrderCountByLOrderId(lOrderId);
        logisticsOrder.setTotalTake(totalTake + sum);
        logisticsOrder.setTotalLoadAmount(loadCount.getAmount().add(totalLoadAmount));
        logisticsOrder.setTotalUnloadAmount(unloadCount.getAmount().add(totalUnloadAmount));
        logisticsOrderDao.updateById(logisticsOrder);

        /*2、物流订单地址运量信息更新*/
        List<KwtLogisticsOrderAmount> amounts = logisticsOrderAmountDao.findByLOrderId(lOrderId);
        for (KwtLogisticsOrderAmount amount : amounts) {
            //物流运单地址信息
            KwtLogisticsOrderAddress address = logisticsOrderAddressDao.selectById(amount.getLAddressId());
            //运单地址进行统计
            BigDecimal totalAmount = waybillOrderTicketService.getAmount(amount.getLAddressId(), logisticsOrder.getUnit(), address.getAddressType());

            if (address.getAddressType().equals(AddressTypeEnum.SHIPMENT.getCode())) {
                amount.setTotalLoadAmount(totalAmount);
            } else {
                amount.setTotalUnloadAmount(totalAmount);
            }
            logisticsOrderAmountDao.updateById(amount);
        }

        /*3、物流订单辅助单位信息更新*/
        kwtLogisticsOrderGoodsService.editLogisticsOrderGoodsTotalLoading(logisticsOrder.getId());

        /*4、递归处理上级物流订单*/
        //获取所有上级物流订单ID
        String pids = logisticsOrder.getPids();
        if (StringUtils.isNotBlank(pids)) {
            String[] idArray = pids.split(Global.COMMA);
            for (String id : idArray) {
                Long pid = Long.parseLong(id);
                //当前物流订单ID除外
                if (!pid.equals(lOrderId)) {
                    /*校验当前承运订单是否运输完成*/
                    editLogisticsTotalCount(pid);
                }
            }
        }
    }

    /**
     * @param wOrderId 运单ID
     * @desc 修改单证查询运单
     * @author zk
     * @date 2024/3/11
     **/
    public HttpResult ticketApproval(Long wOrderId) {
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.ok("车辆运单信息不存在！");
        }

        //操作人
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(wOrderId, null, null);
        List<Long> userIds = tickets.stream().flatMap(item -> Stream.of(item.getCreateBy(), item.getUpdateBy())).toList();
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        /*数据处理*/
        List<Map<String, Object>> addressList = new ArrayList<>();
        List<Integer> typeList = new ArrayList<>() {{
            add(AddressTypeEnum.SHIPMENT.getCode());
            add(AddressTypeEnum.TAKE.getCode());
        }};
        for (Integer type : typeList) {
            //装货地址
            List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByAddresses(wOrderId, type);
            for (KwtWaybillOrderAddress address : addresses) {
                //子单信息
                KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
                //物流订单商品信息
                KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
                //榜单信息
                KwtWaybillOrderTicket ticket = waybillOrderTicketDao.findWaybillOrderTicketV2(address.getId(), subtask.getUnit());
                //辅助单位
                List<WaybillOrderLoadingVO> loading = waybillOrderTicketService.agreementV1(subtask, address.getId());
                Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
                trackData.put("wTicketId", ticket != null ? ticket.getId() : null);
                trackData.put("wOrderId", ticket != null ? ticket.getWOrderId() : null);
                trackData.put("wSubtaskId", subtask.getId());
                trackData.put("wAddressId", address.getId());
                trackData.put("addressType", address.getAddressType());
                trackData.put("urls", ticket != null ? FileUtils.spliceBatch(ticket.getUrls()) : null);
                trackData.put("operateTime", ticket != null ? DateUtil.dateTimeFormatter(ticket.getOperateTime()) : null);
                trackData.put("createTime", ticket != null ? DateUtil.dateTimeFormatter(ticket.getCreateTime()) : null);
                trackData.put("approvalStatus", ticket != null ? ticket.getStatus() : null);
                trackData.put("approvalStatusName", ticket != null ? ApproveStatusEnum.getName(ticket.getStatus()) : null);
                trackData.put("approvalByName", ticket != null && ticket.getStatus() != Global.NUMERICAL_ZERO ? usersMap.get(ticket.getUpdateBy()) != null ? usersMap.get(ticket.getUpdateBy()).getName() : null : null);
                trackData.put("approvalContent", ticket != null && ticket.getStatus() != Global.NUMERICAL_ZERO ? ticket.getRemark() : null);
                trackData.put("approvalTime", ticket != null && ticket.getStatus() != Global.NUMERICAL_ZERO ? ticket.getUpdateTime() : null);
                trackData.put("createByName", ticket != null ? usersMap.get(ticket.getCreateBy()) == null ? waybillOrder.getDriverName() : usersMap.get(ticket.getCreateBy()).getName() : null);
                trackData.put("addressName", address.getName());
                trackData.put("addressCityName", address.getCityName());
                trackData.put("addressDetail", address.getDetailAddress());
                trackData.put("goodsName", goods != null ? goods.getGoodsName() : null);
                trackData.put("unit", subtask.getUnit());
                trackData.put("unitName", unitMap.get(subtask.getUnit()));
                trackData.put("entrustAmount", address.getEntrustAmount());
                trackData.put("loading", loading);
                addressList.add(trackData);
            }
        }

        //数据组装
        Map<String, Object> result = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        result.put("wOrderId", wOrderId);
        result.put("wOrderNo", waybillOrder.getWOrderNo());
        result.put("status", waybillOrder.getStatus());
        result.put("statusName", CarWaybillEnum.getName(waybillOrder.getStatus()));
        result.put("truckNo", waybillOrder.getTruckNo());
        result.put("driverName", waybillOrder.getDriverName());
        result.put("driverPhone", waybillOrder.getDriverPhone());
        result.put("driverIdcard", waybillOrder.getDriverIdcard());
        result.put("createTime", waybillOrder.getCreateTime());
        result.put("addresses", addressList);
        return HttpResult.ok(result);
    }

    /**
     * @param wAddressId 运单地址ID
     * @desc 运单单证信息
     * @author zk
     * @date 2024/3/11
     **/
    public HttpResult ticketInfo(Long wAddressId) {
        //运单地址信息
        KwtWaybillOrderAddress address = waybillOrderAddressDao.selectById(wAddressId);
        if (address == null) {
            return HttpResult.ok("车辆运单地址信息不存在！");
        }
        //车辆运单信息
        Long wOrderId = address.getWOrderId();
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.ok("车辆运单信息不存在！");
        }

        //操作人
        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketDao.findWaybillOrderTicket(wOrderId, null, null);
        List<Long> userIds = tickets.stream().map(KwtWaybillOrderTicket::getCreateBy).toList();
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        //子单信息
        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
        //物流订单商品信息
        KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
        //榜单信息
        KwtWaybillOrderTicket ticket = waybillOrderTicketDao.findWaybillOrderTicketV2(address.getId(), subtask.getUnit());
        //辅助单位
        List<WaybillOrderLoadingVO> loading = waybillOrderTicketService.agreementV1(subtask, address.getId());
        //辅助单位
        List<GoodsUnitVo> assistUnit = kwtLogisticsOrderGoodsService.assistUnit(subtask.getLOrderId());

        //数据组装
        Map<String, Object> result = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        result.put("wOrderId", wOrderId);
        result.put("wOrderNo", waybillOrder.getWOrderNo());
        result.put("status", waybillOrder.getStatus());
        result.put("statusName", CarWaybillEnum.getName(waybillOrder.getStatus()));
        result.put("truckNo", waybillOrder.getTruckNo());
        result.put("driverName", waybillOrder.getDriverName());
        result.put("driverPhone", waybillOrder.getDriverPhone());
        result.put("driverIdcard", waybillOrder.getDriverIdcard());
        result.put("wTicketId", ticket != null ? ticket.getId() : null);
        result.put("wSubtaskId", subtask.getId());
        result.put("wAddressId", address.getId());
        result.put("urls", ticket != null ? FileUtils.spliceBatch(ticket.getUrls()) : null);
        result.put("operateTime", ticket != null ? DateUtil.dateTimeFormatter(ticket.getOperateTime()) : null);
        result.put("approvalStatus", ticket != null ? ticket.getStatus() : null);
        result.put("createByName", ticket != null ? usersMap.get(ticket.getCreateBy()) == null ? waybillOrder.getDriverName() : usersMap.get(ticket.getCreateBy()).getName() : null);
        result.put("createTime", ticket != null ? ticket.getCreateTime() : null);
        result.put("addressName", address.getName());
        result.put("addressCityName", address.getCityName());
        result.put("addressDetail", address.getDetailAddress());
        result.put("goodsName", goods != null ? goods.getGoodsName() : null);
        result.put("unit", subtask.getUnit());
        result.put("unitName", unitMap.get(subtask.getUnit()));
        result.put("amount", ticket != null ? ticket.getAmount() : null);
        result.put("entrustAmount", address.getEntrustAmount());
        result.put("loading", loading);
        result.put("assistUnit", assistUnit);
        return HttpResult.ok(result);
    }

    /**
     * @param wOrderId 运单ID
     * @desc 修改单证查询运单
     * @author zk
     * @date 2024/3/11
     **/
    public HttpResult ticketWaybillOrder(Long wOrderId) {
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.ok("车辆运单信息不存在！");
        }
        //运单状态
        List<KwtWaybillOrderTrack> tracks = waybillOrderTrackDao.findTrack(wOrderId, null, null, null);
        //操作人
        List<Long> userIds = tracks.stream().map(KwtWaybillOrderTrack::getCreateBy).toList();
        List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
        Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        users.forEach(e -> usersMap.put(e.getId(), e));
        //单位
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(DictTypeEnum.UNIT_TYPE.getType()));
        Map<String, String> unitMap = CollectionUtils.isNotEmpty(dict) ? dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>(NumberConstant.SIXTEEN);

        /*数据处理*/
        List<Map<String, Object>> trackList = new ArrayList<>();
        //运单状态(待接单、待出车、出车)
        List<Integer> statusList = CarWaybillEnum.initWaybillStatusV1();
        for (Integer status : statusList) {
            KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrack(wOrderId, null, null, status);
            Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
            trackData.put("id", track != null ? track.getId() : null);
            trackData.put("wOrderId", wOrderId);
            trackData.put("wSubtaskId", track != null ? track.getWSubtaskId() : null);
            trackData.put("wAddressId", track != null ? track.getWAddressId() : null);
            trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
            trackData.put("operateStatus", track != null);
            trackData.put("createTime", track != null ? track.getCreateTime() : null);
            trackData.put("createByName", track != null ? usersMap.get(track.getCreateBy()) == null ? waybillOrder.getDriverName() : usersMap.get(track.getCreateBy()).getName() : null);
            trackData.put("status", status);
            trackData.put("statusName", CarWaybillEnum.getAlias(status));
            trackList.add(trackData);
        }

        //运单状态处理(到达装货点、已装货、到达卸货点、已卸货)
        List<KwtWaybillOrderAddress> addresses = waybillOrderAddressDao.findByAddresses(wOrderId, null);
        for (KwtWaybillOrderAddress address : addresses) {
            if (address.getAddressType().equals(AddressTypeEnum.SHIPMENT.getCode())) {
                statusList = new ArrayList<>() {{
                    add(CarWaybillEnum.WAIT_LOADING.getCode());
                    add(CarWaybillEnum.COMPLETION_LOADING.getCode());
                }};
            } else {
                statusList = new ArrayList<>() {{
                    add(CarWaybillEnum.WAIT_UNLOADING.getCode());
                    add(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
                }};
            }

            //子单信息
            KwtWaybillOrderSubtask subtask = waybillOrderSubtaskDao.selectById(address.getWSubtaskId());
            //物流订单商品信息
            KwtLogisticsOrderGoods goods = logisticsOrderGoodsDao.findByGoods(subtask != null ? subtask.getLOrderId() : null);
            for (Integer status : statusList) {
                //状态记录
                KwtWaybillOrderTrack track = waybillOrderTrackDao.findWaybillOrderTrack(wOrderId, subtask.getId(), address.getId(), status);
                //辅助单位
                List<WaybillOrderLoadingVO> loading = track != null ? waybillOrderTicketService.agreementV1(subtask, track.getWAddressId()) : null;
                //辅助单位
                List<GoodsUnitVo> assistUnit = kwtLogisticsOrderGoodsService.assistUnit(subtask.getLOrderId());
                Map<String, Object> trackData = new HashMap<>(NumberConstant.SIXTEEN);
                trackData.put("id", track != null ? track.getId() : null);
                trackData.put("wOrderId", address.getWOrderId());
                trackData.put("wSubtaskId", address.getWSubtaskId());
                trackData.put("wAddressId", address.getId());
                trackData.put("operateTime", track != null ? DateUtils.format(track.getOperateTime(), DateUtils.FORMAT11) : null);
                trackData.put("operateStatus", track != null);
                trackData.put("createTime", track != null ? track.getCreateTime() : null);
                trackData.put("createByName", track != null ? usersMap.get(track.getCreateBy()) == null ? waybillOrder.getDriverName() : usersMap.get(track.getCreateBy()).getName() : null);
                trackData.put("status", status);
                trackData.put("statusName", CarWaybillEnum.getName(status));
                trackData.put("planTime", track != null ? address.getPlanTime() : null);
                trackData.put("entrustAmount", track != null ? address.getEntrustAmount() : null);
                trackData.put("unit", subtask.getUnit());
                trackData.put("unitName", unitMap.get(subtask.getUnit()));
                trackData.put("goodsName", goods != null ? goods.getGoodsName() : null);
                trackData.put("addressName", address.getName());
                trackData.put("addressCityName", address.getCityName());
                trackData.put("addressDetail", address.getDetailAddress());
                trackData.put("loading", loading);
                trackData.put("assistUnit", assistUnit);
                trackList.add(trackData);
            }
        }

        //数据组装
        Map<String, Object> result = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        result.put("wOrderId", wOrderId);
        result.put("wOrderNo", waybillOrder.getWOrderNo());
        result.put("status", waybillOrder.getStatus());
        result.put("statusName", CarWaybillEnum.getName(waybillOrder.getStatus()));
        result.put("truckNo", waybillOrder.getTruckNo());
        result.put("driverName", waybillOrder.getDriverName());
        result.put("driverPhone", waybillOrder.getDriverPhone());
        result.put("driverIdcard", waybillOrder.getDriverIdcard());
        result.put("createTime", waybillOrder.getCreateTime());
        result.put("trackList", trackList);
        return HttpResult.ok(result);
    }

    /**
     * @param wOrderId 运单ID
     * @desc 变更车辆/司机查询
     * @author zk
     * @date 2023/8/2
     **/
    public HttpResult changeWaybillOrder(@RequestParam("wOrderId") Long wOrderId) {
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(wOrderId);
        if (waybillOrder == null) {
            return HttpResult.error("车辆运单不存在！");
        }

        //数据组装
        Map<String, Object> result = new HashMap<>(NumberConstant.SIXTEEN);
        result.put("id", wOrderId);
        result.put("wOrderId", wOrderId);
        result.put("wOrderNo", waybillOrder.getWOrderNo());
        result.put("statusName", CarWaybillEnum.getName(waybillOrder.getStatus()));
        result.put("truckNo", waybillOrder.getTruckNo());
        result.put("truckId", waybillOrder.getTruckId());
        result.put("driverId", waybillOrder.getDriverId());
        result.put("driverPhone", waybillOrder.getDriverPhone());
        result.put("driverIdcard", waybillOrder.getDriverIdcard());
        result.put("driverName", waybillOrder.getDriverName());
        RTruckVo truck = remoteFleetService.findTruck(waybillOrder.getTruckId());
        result.put("trailerNo", truck != null ? truck.getTrailerNo() : null);
        return HttpResult.ok(result);
    }

    /**
     * @param params 参数
     * @desc 变更司机
     * @author zk
     * @date 2023/8/2
     **/
    public HttpResult changeDriver(@RequestBody @Valid ChangeDriverDto params) {
        /*数据校验*/
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(params.getWOrderId());
        if (waybillOrder == null) {
            return HttpResult.error("车辆运单不存在！");
        }
        if (!CarWaybillEnum.changeDriver(waybillOrder.getStatus())) {
            return HttpResult.error("车辆运单当前状态不能变更司机！");
        }

        /*更新车辆运单**/
        changeWaybillOrder(params, null);
        return HttpResult.ok("更换司机成功！");
    }

    /**
     * @param params 参数
     * @desc 变更车辆
     * @author zk
     * @date 2023/8/2
     **/
    public HttpResult changeTruck(@RequestBody @Valid ChangeTruckDto params) {
        /*数据校验**/
        SckwWaybillOrder wOrder = new SckwWaybillOrder();
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(params.getWOrderId());
        if (waybillOrder == null) {
            return HttpResult.error("车辆运单不存在！");
        }
        if (!CarWaybillEnum.changeTruck(waybillOrder.getStatus())) {
            return HttpResult.error("车辆运单当前状态不能变更车辆！");
        }

        /*更新车辆运单**/
        changeWaybillOrder(null, params);
        return HttpResult.ok("更换车辆成功！");
    }

    /**
     * @param driver 司机信息
     * @param truck  车辆信息
     * @desc 更新车辆运单信息
     * @author zk
     * @date 2023/8/2
     **/
    public void changeWaybillOrder(ChangeDriverDto driver, ChangeTruckDto truck) {
        //车辆运单信息
        KwtWaybillOrderV1 waybillOrder = new KwtWaybillOrderV1();
        if (driver != null) {
            waybillOrder.setId(driver.getWOrderId());
            waybillOrder.setDriverId(driver.getDriverId());
            waybillOrder.setDriverPhone(driver.getDriverPhone());
            waybillOrder.setDriverName(driver.getDriverName());
            waybillOrder.setDriverIdcard(driver.getDriverIdcard());
        }
        if (truck != null) {
            waybillOrder.setId(truck.getWOrderId());
            waybillOrder.setTruckId(truck.getTruckId());
            waybillOrder.setTruckNo(truck.getTruckNo());
        }
        waybillOrderV1Dao.updateById(waybillOrder);
    }

    /**
     * @param driverId 司机档案ID
     * @desc 更新司机信息
     * @author zk
     * @date 2023/8/3
     **/
    public void editDriver(Long driverId) {
        //数据统计
        WaybillCountVo countVo = waybillOrderV1Dao.findCountByDriverOrTruck(driverId, null);
        WaybillCountVo amountVo = waybillOrderV1Dao.findAmountByDriverOrTruck(driverId, null);
        RDriverVo driver = new RDriverVo();
        driver.setId(driverId);
        driver.setTotalComplete(countVo.getTotalComplete());
        driver.setTotalTake(countVo.getTotalTake());
        driver.setTotalWeight(amountVo.getLoadAmount());
        driver.setBusinessStatus(countVo.getTotalExecute() > 0 ? 1 : 0);
        remoteFleetService.updateById(driver);
    }

    /**
     * @param truckId 车辆档案ID
     * @desc 更新车辆信息
     * @author zk
     * @date 2023/8/3
     **/
    public void editTruck(Long truckId) {
        //数据统计
        WaybillCountVo countVo = waybillOrderV1Dao.findCountByDriverOrTruck(null, truckId);
        WaybillCountVo amountVo = waybillOrderV1Dao.findAmountByDriverOrTruck(null, truckId);
        RTruckVo truck = new RTruckVo();
        truck.setId(truckId);
        truck.setTotalComplete(countVo.getTotalComplete());
        truck.setTotalTake(countVo.getTotalTake());
        truck.setTotalWeight(amountVo.getLoadAmount());
        truck.setBusinessStatus(countVo.getTotalExecute() > 0 ? 1 : 0);
        remoteFleetService.updateById(truck);
    }

    /**
     * @param type  字典类型
     * @param value 字典值
     * @desc 获取数据字典值
     * @author zk
     * @date 2023/8/30
     **/
    public String getDictValue(String type, String value) {
        if (StringUtils.isBlank(type) || StringUtils.isBlank(value)) {
            return null;
        }
        List<String> dictKey = new ArrayList<>() {{
            add(type + Global.POUND + value);
        }};
        Map<String, SysDictResDto> dicts = remoteSystemService.queryDictMapByTypeValues(String.join(Global.COMMA, dictKey));
        SysDictResDto dict = dicts == null ? null : dicts.get(DictTypeEnum.APPROVED_DRIVING.getType() + Global.POUND + value);
        return dict != null ? dict.getLabel() : null;
    }

    /**
     * @param dictKey 字典值
     * @desc 获取数据字典
     * @author zk
     * @date 2023/9/11
     **/
    public Map<String, SysDictResDto> dict(List<String> dictKey) {
        if (CollectionUtils.isEmpty(dictKey)) {
            return Collections.emptyMap();
        }
        dictKey = dictKey.stream().distinct().collect(Collectors.toList());
        return remoteSystemService.queryDictMapByTypeValues(String.join(Global.COMMA, dictKey));
    }

    /**
     * @param loadAmount    装货量
     * @param deficitAmount 亏吨量
     * @param loss          合理损耗
     * @param goodsPrice    货值单价
     * @desc 计算亏吨扣款
     * @author zk
     * @date 2023/7/27
     **/
    public static BigDecimal deficitPrice(BigDecimal loadAmount, BigDecimal deficitAmount, BigDecimal loss,
                                          String lossUnit, BigDecimal goodsPrice) {
        //亏吨<=0
        if (deficitAmount == null || deficitAmount.doubleValue() <= 0) {
            return new BigDecimal(Global.AMOUNT);
        }
        //承运订单亏吨扣款=（承运订单亏吨量 -（承运订单装货量 * 承运订单合理损耗））* 扣亏货值
        loss = loss == null ? new BigDecimal(Global.AMOUNT) : loss;
        if (loss.doubleValue() > 0 && StringUtils.isNotBlank(lossUnit)) {
            if (lossUnit.equals(String.valueOf(TaxRateTypeEnum.PERCENT.getCode()))) {
                loss = loss.divide(new BigDecimal(TaxRateTypeEnum.PERCENT.getValue()));
            }
            if (lossUnit.equals(String.valueOf(TaxRateTypeEnum.MILLIMETER.getCode()))) {
                loss = loss.divide(new BigDecimal(TaxRateTypeEnum.MILLIMETER.getValue()));
            }
        }

        goodsPrice = goodsPrice == null ? new BigDecimal(Global.AMOUNT) : goodsPrice;
        BigDecimal deficitLossAmount = deficitAmount.subtract(loadAmount.multiply(loss).setScale(2, RoundingMode.HALF_UP));
        //扣亏量=亏吨量-合理损耗值【要求大于0，如果小于0则扣亏货量取0】
        if (deficitLossAmount.doubleValue() <= 0) {
            return new BigDecimal(Global.AMOUNT);
        }
        //罚款值=扣亏量 * 扣亏货值
        return deficitLossAmount.multiply(goodsPrice).setScale(4, RoundingMode.HALF_UP);
    }

    /**
     * @param params
     * @desc 订单信息
     * @author zk
     * @date 2024/3/13
     **/
    public WaybillOrderDetailVo queryBillOrderInfo(WaybillOrderRequest params) {
        if (params.getOrderId() == null) {
            throw new RuntimeException("运单号id不能为空");
        }
        //运单信息
        KwtWaybillOrderV1 waybillOrder = waybillOrderV1Dao.selectById(params.getOrderId());
        if (waybillOrder == null) {
            throw new RuntimeException("运单" + params.getOrderId() + "不存在，请确认！");
        }
        WaybillOrderDetailVo orderDetailVo = new WaybillOrderDetailVo();
        //车队车辆映射关系
        RFleetDriverVo fleetByDriveId = remoteFleetService.findFleetByDriveId(waybillOrder.getDriverId());
        if  (fleetByDriveId == null) {
            throw new RuntimeException("运单:" + params.getOrderId() + ", 车辆信息不存在，请确认！");
        }

        //查询车辆信息
        RFleetVo fleetVO = remoteFleetService.findFleetById(fleetByDriveId.getFleetId());
        orderDetailVo.setDriverId(waybillOrder.getDriverId());
        orderDetailVo.setDriverName(waybillOrder.getDriverName());
        orderDetailVo.setTruckNo(waybillOrder.getTruckNo());
        orderDetailVo.setFleetId(fleetByDriveId.getFleetId());
        orderDetailVo.setFleetName(Optional.ofNullable(fleetVO).map(RFleetVo::getName).orElse(""));

        //查询企业信息
        KwsEnterpriseResDto entCacheResDto = remoteSystemService.queryEnterpriseByEntId(waybillOrder.getEntId());
        orderDetailVo.setEntId(waybillOrder.getEntId());
        orderDetailVo.setEntName(Optional.ofNullable(entCacheResDto).map(KwsEnterpriseResDto::getFirmName).orElse(""));

        //查询位置信息
        List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressRepository.queryBywOrderIds(Arrays.asList(waybillOrder.getId()));
        if (CollectionUtils.isEmpty(orderAddresses)) {
            throw new RuntimeException("运单:" + params.getOrderId() + ", 地址信息不存在，请确认！");
        }

        Map<Integer, String> addressNameMap = orderAddresses.stream()
                .filter(address -> address.getAddressType() != null && (address.getAddressType() == 1 || address.getAddressType() == 2))
                .collect(Collectors.groupingBy(
                        KwtWaybillOrderAddress::getAddressType,
                        Collectors.collectingAndThen(
                                Collectors.mapping(KwtWaybillOrderAddress::getName, Collectors.toList()),
                                list -> list.isEmpty() ? "" : list.get(0)
                        )
                ));
        orderDetailVo.setAddresses(addressNameMap);

        return orderDetailVo;
    }


    public PageDataResult<WaybillOrderResp> findBillOrderListPage(WaybillOrderReq req) {
        log.info("查询订单列表请求参数：{}", JSON.toJSONString(req));
        KwtLogisticsOrder logisticsOrder = new KwtLogisticsOrder() ;
        if (StringUtils.isNotBlank(req.getLogisticsOrderId())){
            log.debug("查询物流订单ID: {}", req.getLogisticsOrderId());
            logisticsOrder = logisticsOrderRepository.queryByLogisticsOrderId(Long.valueOf(req.getLogisticsOrderId()));
        }

        // 处理状态参数
        Integer status = parseStatus(req.getStatus());

        // 使用CompletableFuture并行执行不相互依赖的查询
        log.debug("开始并行查询物流订单ID和运单ID");
        // 根据企业ID查询物流订单

        Set<Long> entIds = getEnterpriseIds(req);
        Long entId =LoginUserHolder.getEntId();
        //entIds.add(entId);
        log.debug("获取企业ID集合: {}", entIds);

        CompletableFuture<Set<Long>> logOrderIdsFuture = CompletableFuture.supplyAsync(() -> {
            log.debug("开始查询物流订单ID，参数: {}, 企业ID: {}", JSON.toJSONString(req), entIds);
            Set<Long> result = getLogOrderIds(req, entIds,entId);
            log.debug("物流订单ID查询完成，结果数量: {}", result.size());
            return result;
        });

        CompletableFuture<Set<Long>> billOrderIdsFuture = CompletableFuture.supplyAsync(() -> {
            log.debug("开始查询运单ID，参数: {}", req);
            Set<Long> result = getBillOrderIds(req);
            log.debug("运单ID查询完成，结果数量: {}", result.size());
            return result;
        });

        CompletableFuture<Map<String, Map<String, String>>> dictFuture = CompletableFuture.supplyAsync(() -> {
            log.debug("开始查询字典数据");
            Map<String, Map<String, String>> result = queryDictionaryData();
            log.debug("字典数据查询完成");
            return result;
        },traceTaskExecutor).exceptionally(ex -> {
            log.error("字典查询失败", ex);
            throw new BusinessException("字典查询失败");
        });

        // 等待物流订单ID和运单ID查询完成
        log.debug("等待物流订单ID和运单ID查询完成");
        CompletableFuture.allOf(logOrderIdsFuture, billOrderIdsFuture).join();

        Set<Long> logOrderIds = logOrderIdsFuture.join();
        Set<Long> billOrderIds = billOrderIdsFuture.join();
        log.debug("物流订单ID查询结果数量: {}, 运单ID查询结果数量: {}", logOrderIds.size(), billOrderIds.size());

        // 数据权限：企业按 kwt_logistics_order_unit；个人按贸易合同销售员（见 applyDataPermissionFilterToLogOrderIds）
        logOrderIds = applyDataPermissionFilterToLogOrderIds(logOrderIds);
        log.debug("数据权限过滤后物流订单ID数量: {}", logOrderIds.size());

        // 检查是否需要返回空结果
        log.debug("检查是否需要返回空结果");
        if (shouldReturnEmptyResultForLogistics(req, logOrderIds) ||
                shouldReturnEmptyResultForWaybill(req, billOrderIds)) {
            log.info("根据查询条件返回空结果");
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        // 分页查询子运单信息
        log.info("开始分页查询子运单信息，物流订单ID数量: {}, 运单ID数量: {}, 状态: {}",
                logOrderIds.size(), billOrderIds.size(), status);
        List<Integer> waybillOrderStatus = getWaybillOrderStatus();
        IPage<KwtWaybillOrderSubtask> page = waybillOrderSubtaskRepository.queryByPage(
                logOrderIds, billOrderIds, status,waybillOrderStatus, req.getPageNum(), req.getPageSize());

        List<KwtWaybillOrderSubtask> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            log.info("查询结果为空，返回空分页结果");
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        log.info("查询到子运单记录数量: {}", records.size());

        // 提取ID集合
        log.debug("开始提取订单ID集合");
        OrderIds orderIds = extractOrderIds(records);

        // 并行执行批量查询和获取字典数据
        log.debug("开始并行执行订单数据查询");
        CompletableFuture<OrderData> orderDataFuture = CompletableFuture.supplyAsync(() -> {
            log.debug("开始查询订单数据，订单ID数量: {}", orderIds.getWayBillOrderIds().size());
            OrderData result = batchQueryOrderData(orderIds);
            log.debug("订单数据查询完成");
            return result;
        }, traceTaskExecutor).exceptionally(ex -> {
            log.error("查询订单失败", ex);
            throw new BusinessException("查询订单失败");
        });

        log.debug("开始查询物流订单，物流订单ID数量: {}", orderIds.getLogicsOrderIds().size());
        CompletableFuture<List<KwtLogisticsOrder>> logisticsOrderFuture = CompletableFuture.supplyAsync(() ->
                logisticsOrderRepository.queryByLogOrderIds(orderIds.getLogicsOrderIds()), traceTaskExecutor)
                .exceptionally(ex -> {
                    log.error("查询物流订单失败", ex);
                    throw new BusinessException("查询物流订单失败");
                });

        log.debug("开始查询商品信息，物流订单ID数量: {}", orderIds.getLogicsOrderIds().size());
        CompletableFuture<List<KwtLogisticsOrderGoods>> goodsInfoFuture = CompletableFuture.supplyAsync(() ->
                        kwtLogisticsOrderGoodsRepository.queryByLogIds(new ArrayList<>(orderIds.getLogicsOrderIds())), traceTaskExecutor)
                .exceptionally(ex -> {
                    log.error("查询物流商品失败", ex);
                    throw new BusinessException("查询物流商品失败");
                });

        // ====== 提取 tradeOrderIds ======
        CompletableFuture<Set<Long>> tradeOrderIdsFuture = CompletableFuture.completedFuture(Collections.emptySet());
        CompletableFuture<Set<Long>> goodsIdsFuture = CompletableFuture.completedFuture(Collections.emptySet());
        CompletableFuture<List<TradeOrderContractVo>> tradeOrderContractFuture = CompletableFuture.completedFuture(Collections.emptyList());
        CompletableFuture<List<TradeContractGoodsDto>> contractGoodsFuture = CompletableFuture.completedFuture(Collections.emptyList());
        if (Objects.nonNull(logisticsOrder) && !Objects.equals(logisticsOrder.getOrderType(), 1)) {
            log.info("非原矿订单，订单iD: {}, 订单类型: {}", logisticsOrder.getId(), logisticsOrder.getOrderType());
            log.debug("开始提取贸易订单ID");
            tradeOrderIdsFuture =
                    logisticsOrderFuture.thenApply(list -> {
                        log.debug("物流订单数据处理完成，数量: {}", list.size());
                        return list.stream()
                                .map(KwtLogisticsOrder::getTOrderId)
                                .filter(Objects::nonNull)
                                .collect(Collectors.toSet());
                    });

            // ====== 提取 goodsIds ======
            log.debug("开始提取商品ID");
            goodsIdsFuture =
                    goodsInfoFuture.thenApply(list -> {
                        log.debug("商品信息数据处理完成，数量: {}", list.size());
                        return list.stream()
                                .map(KwtLogisticsOrderGoods::getGoodsId)
                                .filter(Objects::nonNull)
                                .collect(Collectors.toSet());
                    }).handle(((goodsIds, ex) -> {
                        if (ex != null) {
                            log.error("查询商品ID失败", ex);
                            return Set.of();
                        } else {
                            log.debug("商品ID提取完成，数量: {}", goodsIds.size());
                            return goodsIds;
                        }
                    }));

            // ====== 查询贸易订单合同 ======
            log.debug("开始查询贸易订单合同");
            tradeOrderContractFuture =
                    tradeOrderIdsFuture.thenCompose(tradeOrderIds -> {
                        log.debug("贸易订单ID准备完成，数量: {}", tradeOrderIds.size());
                        return CompletableFuture.supplyAsync(() -> {
                            log.debug("开始查询贸易订单合同，贸易订单ID数量: {}", tradeOrderIds.size());
                            List<TradeOrderContractVo> result = tradeOrderInfoService.queryTradeOrderIds(tradeOrderIds);
                            log.debug("贸易订单合同查询完成，数量: {}", result.size());
                            return result;
                        });
                    }).exceptionally(ex -> {
                        log.error("查询贸易订单合同失败", ex);
                         return List.of();
                       // throw new BusinessException("查询贸易订单合同失败");
                    });

            // ====== 查询贸易合同商品 ======
            log.debug("开始查询贸易合同商品");
            contractGoodsFuture =
                    tradeOrderContractFuture.thenCombine(goodsIdsFuture, (contracts, goodsIds) -> {
                                log.debug("贸易合同和商品ID准备完成，合同数量: {}, 商品ID数量: {}",
                                        Optional.ofNullable(contracts).map(List::size).orElse(0),
                                        goodsIds.size());
                                Set<Long> contractIds = Optional.ofNullable(contracts)
                                        .orElse(List.of())
                                        .stream()
                                        .map(TradeOrderContractVo::getContractId)
                                        .filter(Objects::nonNull)
                                        .collect(Collectors.toSet());
                                log.debug("合同ID提取完成，数量: {}", contractIds.size());
                                List<TradeContractGoodsDto> result = remoteContractService.queryContractGoodsByContractIds(contractIds, goodsIds);
                                log.debug("贸易合同商品查询完成，数量: {}", result.size());
                                return result;
                            }).thenApply(goods -> Optional.ofNullable(goods).orElse(List.of()))
                            .exceptionally(ex -> {
                                log.error("查询贸易订单商品失败", ex);
                                return List.of();
                               // throw new BusinessException("查询贸易订单商品失败");
                            });

            log.debug("所有异步任务创建完成");

        }



        // 等待所有并行操作完成
        log.debug("等待所有并行操作完成");
        try {
            CompletableFuture.allOf(
                    orderDataFuture,
                    logisticsOrderFuture,
                    goodsInfoFuture,
                    tradeOrderIdsFuture,
                    goodsIdsFuture,
                    tradeOrderContractFuture,
                    dictFuture,
                    contractGoodsFuture
            ).orTimeout(30, TimeUnit.SECONDS).join();

        } catch (Exception e) {
            log.error("执行超时或异常", e);
        }
        log.debug("所有并行操作完成");
        OrderData orderData = orderDataFuture.join();
        Map<String, Map<String, String>> dictValueAndDictResDtoMap = dictFuture.join();
        log.debug("批量查询和字典数据获取完成");
        Map<Long, KwtLogisticsOrder> logisticsOrderMap = Optional.ofNullable(logisticsOrderFuture.join())
                .orElse(List.of()).stream()
                .collect(Collectors.toMap(KwtLogisticsOrder::getId, Function.identity(), (k1, k2) -> k1));

        Map<Long, TradeOrderContractVo> tradeOrderContractVoMap = Optional.ofNullable(tradeOrderContractFuture.join())
                .orElse(List.of()).stream()
                .collect(Collectors.toMap(TradeOrderContractVo::getTOrderId, Function.identity(), (k1, k2) -> k1));
        Map<String, TradeContractGoodsDto> orderContracGoodstoMap = Optional.ofNullable(contractGoodsFuture.join())
                .orElse(List.of()).stream()
                .collect(Collectors.toMap(x->x.getContractId()+"-"+x.getGoodsId(), Function.identity(), (k1, k2) -> k1));

        // 转换为响应对象
        log.debug("开始转换为响应对象");
        List<WaybillOrderResp> resps = convertToWaybillOrderRespList(
                records, orderData, dictValueAndDictResDtoMap,logisticsOrderMap, tradeOrderContractVoMap,orderContracGoodstoMap);
        log.info("转换完成，响应对象数量: {}", resps.size());

        return PageDataResult.of(page, resps);
    }


    /**
     * 解析状态参数
     */
    private Integer parseStatus(String statusStr) {
        return StringUtils.isNotBlank(statusStr) ? Integer.parseInt(statusStr) : null;
    }

    /**
     * 检查是否需要返回空结果（物流订单相关）
     */
    private boolean shouldReturnEmptyResultForLogistics(WaybillOrderReq req, Set<Long> logOrderIds) {
        boolean hasLogisticsFilter = Stream.of(
                        req.getLogisticsOrderNo(), req.getGoodsName(),
                        req.getCarrierId(), req.getConsignorId(), req.getLogisticsOrderId())
                .anyMatch(StringUtils::isNotBlank);

        boolean hasEnterpriseFilter = Objects.nonNull(LoginUserHolder.getEntId());

        return CollectionUtils.isEmpty(logOrderIds) && (hasLogisticsFilter || hasEnterpriseFilter);
    }

    /**
     * 检查是否需要返回空结果（运单相关）
     */
    private boolean shouldReturnEmptyResultForWaybill(WaybillOrderReq req, Set<Long> billOrderIds) {
        boolean hasWaybillFilter = Stream.of(
                        req.getWaybillNo(), req.getTruckNo(), req.getDriverName(), req.getPhone(),
                        req.getLoadStartTime(), req.getLoadEndTime(), req.getUnloadStartTime(), req.getUnloadEndTime())
                .anyMatch(StringUtils::isNotBlank);

        return CollectionUtils.isEmpty(billOrderIds) && hasWaybillFilter;
    }

    /**
     * 提取订单ID集合
     */
    private OrderIds extractOrderIds(List<KwtWaybillOrderSubtask> records) {
        OrderIds orderIds = new OrderIds();

        records.forEach(record -> {
            orderIds.getWayBillOrderIds().add(record.getWOrderId());
            orderIds.getLogicsOrderIds().add(record.getLOrderId());
            orderIds.getSubWayBillOrderIds().add(record.getId());
        });

        return orderIds;
    }

    /**
     * 批量查询订单相关数据
     */
    private OrderData batchQueryOrderData(OrderIds orderIds) {
        OrderData orderData = new OrderData();

        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryByBillOrderIds(orderIds.getWayBillOrderIds());

        // 查询主运单信息
        orderData.setWaybillOrderMap(getLongKwtWaybillOrderMap(waybillOrders));

        // 查询承运托运单位信息
        orderData.setLogisticsOrderUnitMap(getStringKwtLogisticsOrderUnitMap(
                new ArrayList<>(orderIds.getLogicsOrderIds())));

        // 查询装卸货地址
        queryOrderAddresses(orderIds, orderData);

        // 查询运单节点数据
        queryOrderNodes(orderIds, orderData);

        // 查询商品信息
        queryGoodsInfo(orderIds, orderData);

        // 查询物流订单信息
        queryLogisticsOrders(orderIds, orderData);

        // 轴数
        queryCarAxis(waybillOrders, orderData);

        //装卸货信息
        queryTareAndGrossAmount(waybillOrders, orderData);

        return orderData;
    }

    /**
     * 查询装卸货地址
     */
    private void queryOrderAddresses(OrderIds orderIds, OrderData orderData) {
        List<KwtWaybillOrderAddress> orderAddresses = waybillOrderAddressRepository.queryBySubBillOrderId(
                orderIds.getSubWayBillOrderIds());

        if (CollectionUtils.isNotEmpty(orderAddresses)) {
            orderData.setSubOrderIdAddressTypeKeyAndAddressMap(
                    orderAddresses.stream()
                            .peek(x -> x.setSubOrderIdAddressTypeKey(x.getWSubtaskId() + "-" + x.getAddressType()))
                            .collect(Collectors.toMap(
                                    KwtWaybillOrderAddress::getSubOrderIdAddressTypeKey,
                                    Function.identity(),
                                    (k1, k2) -> k1)));

            Set<Long> addressIds = orderAddresses.stream()
                    .map(KwtWaybillOrderAddress::getId)
                    .collect(Collectors.toSet());
            orderData.setAddressIds(addressIds);
        } else {
            orderData.setSubOrderIdAddressTypeKeyAndAddressMap(Maps.newHashMap());
        }
    }

    /**
     * 查询运单节点数据
     */
    private void queryOrderNodes(OrderIds orderIds, OrderData orderData) {
        // 查询所有运单的节点数据，过滤出状态为"已离场"的节点
        List<Integer> statusList = Arrays.asList(
                CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
                CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
                CarWaybillV1Enum.COMPLETION_LOADING.getCode());

        List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.queryNodes(
                orderIds.getWayBillOrderIds(), statusList);

        if (CollectionUtils.isNotEmpty(nodes)) {
            orderData.setWaybillOrderNodeMap(
                    nodes.stream()
                            .collect(Collectors.toMap(
                                    x -> x.getWOrderId() + "-" + x.getOrderStatus(),
                                    Function.identity(),
                                    (k1, k2) -> k1)));
        } else {
            orderData.setWaybillOrderNodeMap(Maps.newHashMap());
        }

        // 查询运单节点数据，获取离场时间
        orderData.setWOrderIdAndOffsiteNodeMap(getOffsiteNodeMap(orderIds.getWayBillOrderIds()));
    }


    /**
     * 查询商品信息
     * 根据物流订单ID列表查询对应的商品信息，并构建物流订单ID到商品信息的映射以及商品ID到商品详情的映射
     */
    private void queryGoodsInfo(OrderIds orderIds, OrderData orderData) {
        // 根据物流订单查询商品
        List<KwtLogisticsOrderGoods> logisticsOrderGoods = kwtLogisticsOrderGoodsRepository.queryByLogOrderIds(
                new ArrayList<>(orderIds.getLogicsOrderIds()));

        if (CollectionUtils.isNotEmpty(logisticsOrderGoods)) {
            List<Long> goodsIds = logisticsOrderGoods.stream()
                    .map(KwtLogisticsOrderGoods::getGoodsId)
                    .distinct()
                    .collect(Collectors.toList());

            // 构建物流订单ID到商品信息的映射
            orderData.setLogOrderIdAndGoodsIdMap(
                    logisticsOrderGoods.stream()
                            .collect(Collectors.toMap(
                                    KwtLogisticsOrderGoods::getLOrderId,
                                    Function.identity(),
                                    (k1, k2) -> k1)));

            // 根据商品ID列表查询商品详情并构建映射
            orderData.setKwpGoodsMap(goodsInfoService.getGoodsByIds(goodsIds));
        } else {
            // 如果没有查询到商品信息，则初始化空的映射
            orderData.setLogOrderIdAndGoodsIdMap(Maps.newHashMap());
            orderData.setKwpGoodsMap(Maps.newHashMap());
        }
    }

    /**
     * 查询物流订单信息
     */
    private void queryLogisticsOrders(OrderIds orderIds, OrderData orderData) {
        List<KwtLogisticsOrder> kwtLogisticsOrders = kwtLogisticsOrderRepository.queryByLogisticsOrderIds(
                new ArrayList<>(orderIds.getLogicsOrderIds()));

        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)) {
            orderData.setLogIdAndOrderMap(
                    kwtLogisticsOrders.stream()
                            .collect(Collectors.toMap(
                                    KwtLogisticsOrder::getId,
                                    Function.identity(),
                                    (k1, k2) -> k1)));
        } else {
            orderData.setLogIdAndOrderMap(Maps.newHashMap());
        }
    }

    /**
     * 查询运单轴数
     */
    private void queryCarAxis(List<KwtWaybillOrder> waybillOrders, OrderData orderData) {
        List<Long> truckIds = waybillOrders.stream().map(KwtWaybillOrder::getTruckId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<RTruckVo> truckVoList = remoteFleetService.findTruckByTruckIds(truckIds);
        if (CollectionUtils.isNotEmpty(truckVoList)) {
            Map<Long, RTruckVo> truckVoMap = truckVoList.stream().collect(Collectors.toMap(RTruckVo::getId, Function.identity(), (x, y) -> x));
            orderData.setCarAxisMap(truckVoMap);
        }
    }

    /**
     *
     * 查询运单皮重、毛重
     * @param waybillOrders
     */
    private void queryTareAndGrossAmount(List<KwtWaybillOrder> waybillOrders, OrderData orderData) {
        List<Long> wbOrderIdList = waybillOrders.stream().map(KwtWaybillOrder::getId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<KwtWaybillOrderTicket> orderTicketList = kwtWaybillOrderTicketRepository.queryByWOrderIds(wbOrderIdList);
        if (CollectionUtils.isNotEmpty(orderTicketList)) {
            Map<String, KwtWaybillOrderTicket> ticketMap = orderTicketList.stream().collect(
                    Collectors.toMap(ticket -> ticket.getWOrderId() + "-" + ticket.getType(),
                            Function.identity(), (x, y) -> x));
            orderData.setTicketMap(ticketMap);
        }
    }

    /**
     * 查询字典数据
     */
    private Map<String, Map<String, String>> queryDictionaryData() {
        return remoteSystemService.queryDictByType(Arrays.asList(
                DictTypeEnum.PRODUCT_NAME_TYPE.getType(),
                DictTypeEnum.GOODS_SPEC.getType()));
    }

    /**
     * 转换为WaybillOrderResp列表
     */
    private List<WaybillOrderResp> convertToWaybillOrderRespList(
            List<KwtWaybillOrderSubtask> records,
            OrderData orderData,
            Map<String, Map<String, String>> dictValueAndDictResDtoMap,
            Map<Long, KwtLogisticsOrder> logisticsOrderMap,
            Map<Long, TradeOrderContractVo> tradeOrderContractVoMap,
            Map<String, TradeContractGoodsDto> orderContracGoodstoMap) {

        return records.stream()
                .map(record -> buildWaybillOrderResp(record, orderData, dictValueAndDictResDtoMap,logisticsOrderMap, tradeOrderContractVoMap,orderContracGoodstoMap))
                .collect(Collectors.toList());
    }

    /**
     * 构建WaybillOrderResp对象
     */
    private WaybillOrderResp buildWaybillOrderResp(
            KwtWaybillOrderSubtask record,
            OrderData orderData,
            Map<String, Map<String, String>> dictValueAndDictResDtoMap,
            Map<Long, KwtLogisticsOrder> logisticsOrderMap,
            Map<Long, TradeOrderContractVo> tradeOrderContractVoMap,
            Map<String, TradeContractGoodsDto> orderContracGoodstoMap) {

        return getWaybillOrderResp(
                record,
                orderData.getWaybillOrderMap(),
                orderData.getLogisticsOrderUnitMap(),
                orderData.getLogOrderIdAndGoodsIdMap(),
                orderData.getKwpGoodsMap(),
                orderData.getSubOrderIdAddressTypeKeyAndAddressMap(),
                orderData.getWaybillOrderNodeMap(),
                orderData.getLogIdAndOrderMap(),
                dictValueAndDictResDtoMap,
                orderData.getWOrderIdAndOffsiteNodeMap(),
                orderData.getCarAxisMap(),
                orderData.getTicketMap(),
                logisticsOrderMap,
                tradeOrderContractVoMap,
                orderContracGoodstoMap);
    }

    public WaybillOrderSaleVo saleSum() {
        LocalDate now = LocalDate.now();
        LocalDateTime localDateTime = now.atStartOfDay();
        LocalDateTime startOfTomorrow = now.plusDays(1).atStartOfDay();
        //石灰石
        WaybillOrderSaleDto waybillOrderSaleDto = waybillOrderV1Dao.saleSum(List.of("002", "0001", "0002", "0003", "0004", "0005", "0006"),localDateTime,startOfTomorrow);
        //氧化钙
        WaybillOrderSaleDto waybillOrderSaleDto2 = waybillOrderV1Dao.saleSum(List.of("003", "0007", "0008", "0009"),localDateTime,startOfTomorrow);
        WaybillOrderSaleVo waybillOrderSaleVo = new WaybillOrderSaleVo();
        waybillOrderSaleVo.setShsChl(Objects.nonNull(waybillOrderSaleDto) ? waybillOrderSaleDto.getChl() : BigDecimal.ZERO);
        waybillOrderSaleVo.setShsXsl(Objects.nonNull(waybillOrderSaleDto) ? waybillOrderSaleDto.getXsl() : BigDecimal.ZERO);
        waybillOrderSaleVo.setYhgChl(Objects.nonNull(waybillOrderSaleDto2) ? waybillOrderSaleDto2.getChl() : BigDecimal.ZERO);
        waybillOrderSaleVo.setYhgXsl(Objects.nonNull(waybillOrderSaleDto2) ? waybillOrderSaleDto2.getXsl() : BigDecimal.ZERO);

        return waybillOrderSaleVo;
    }

    /**
     * 订单ID集合容器
     */
    @Data
    private static class OrderIds {
        private Set<Long> wayBillOrderIds = Sets.newHashSet();
        private Set<Long> logicsOrderIds = Sets.newHashSet();
        private Set<Long> subWayBillOrderIds = Sets.newHashSet();
    }

    /**
     * 订单数据容器
     */
    @Data
    private static class OrderData {
        private Map<Long, KwtWaybillOrder> waybillOrderMap;
        private Map<String, KwtLogisticsOrderUnit> logisticsOrderUnitMap;
        private Map<String, KwtWaybillOrderAddress> subOrderIdAddressTypeKeyAndAddressMap;
        private Set<Long> addressIds;
        private Map<String, KwtWaybillOrderNode> waybillOrderNodeMap;
        private Map<Long, KwtWaybillOrderNode> wOrderIdAndOffsiteNodeMap;
        private Map<Long, KwtLogisticsOrderGoods> logOrderIdAndGoodsIdMap;
        private Map<Long, KwpGoods> kwpGoodsMap;
        private Map<Long, KwtLogisticsOrder> logIdAndOrderMap;
        private Map<Long, RTruckVo> carAxisMap;
        private Map<String, KwtWaybillOrderTicket> ticketMap;
    }


    @NotNull
    private Map<Long, KwtWaybillOrder> getLongKwtWaybillOrderMap(List<KwtWaybillOrder> waybillOrders) {
        Map<Long, KwtWaybillOrder> waybillOrderIdAndBillOrderMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(waybillOrders)){
            waybillOrderIdAndBillOrderMap = waybillOrders.stream()
                    .collect(Collectors.toMap(KwtWaybillOrder::getId, Function.identity(), (k1, k2) -> k1));
        }
        return waybillOrderIdAndBillOrderMap;
    }
    @NotNull
    private Set<Long> getAllEnt(WaybillOrderReq req) {
        Set<Long> allEnt = Sets.newHashSet();
        //根据企业类型查询企业
        if (StringUtils.isBlank(req.getEntId())){
            req.setEntId(String.valueOf(LoginUserHolder.getEntId()));
        }

        if (StringUtils.isBlank(req.getEntId())){
            return allEnt;
        }
        allEnt.add( Long.parseLong(req.getEntId()));
        EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(Long.parseLong(req.getEntId()));
        if (Objects.nonNull(entCacheResDto)) {
            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntTreeById(entCacheResDto.getId());
            List<EntCacheResDto> child = entCacheResDto1.getChild();
            if (CollectionUtils.isNotEmpty(child)) {
                allEnt.addAll(child.stream()
                        .map(EntCacheResDto::getId).toList());
            }
        }
        return allEnt;
    }

    @NotNull
    private Map<String, KwtLogisticsOrderUnit> getStringKwtLogisticsOrderUnitMap(List<Long> logicsOrderIds) {
        List<KwtLogisticsOrderUnit> logisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByLogOrderIds(logicsOrderIds);
        Map<String, KwtLogisticsOrderUnit> logOrderIdUnitTypeKeyAndUnitMap = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(logisticsOrderUnits)){
            logOrderIdUnitTypeKeyAndUnitMap =
                    logisticsOrderUnits.stream()
                    .collect(Collectors.toMap(x -> x.getLOrderId() + "-" + x.getUnitType(),
                            Function.identity(), (k1, k2) -> k1));
        }
        return logOrderIdUnitTypeKeyAndUnitMap;
    }

    @NotNull
    private Map<String, KwtWaybillOrderTicket> getStringKwtWaybillOrderTrackMap(Set<Long> addressIds) {
        List<KwtWaybillOrderTicket> kwtWaybillOrderTracks = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(addressIds)){
            // kwtWaybillOrderTracks = kwtWaybillOrderTrackRepository.queryByAddressIds(addressIds);
             kwtWaybillOrderTracks = kwtWaybillOrderTicketRepository.queryByAddressIds(addressIds);
        }
        Map<String, KwtWaybillOrderTicket> subBillIdAddressIdKeyAndOrderTrackMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)){
            subBillIdAddressIdKeyAndOrderTrackMap =
                    kwtWaybillOrderTracks.stream()
                            .collect(Collectors.toMap(x -> x.getWSubtaskId() + "-" + x.getWAddressId(),
                                    Function.identity(), (k1, k2) -> k1));
        }
        return subBillIdAddressIdKeyAndOrderTrackMap;
    }

    /**
     * 批量查询运单的离场节点
     * @param wOrderIds 运单ID集合
     * @return 运单ID对应的离场节点Map
     */
    @NotNull
    private Map<Long, KwtWaybillOrderNode> getOffsiteNodeMap(Set<Long> wOrderIds) {
        Map<Long, KwtWaybillOrderNode> offsiteNodeMap = Maps.newHashMap();

        if (CollectionUtils.isEmpty(wOrderIds)) {
            return offsiteNodeMap;
        }

        // 查询所有运单的节点数据，过滤出状态为“已离场”的节点
        List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.list(
                Wrappers.<KwtWaybillOrderNode>lambdaQuery()
                        .in(KwtWaybillOrderNode::getWOrderId, wOrderIds)
                        .eq(KwtWaybillOrderNode::getOrderStatus, CarWaybillV1Enum.WAIT_LOADING.getCode())
                        .orderByAsc(KwtWaybillOrderNode::getCreateTime)
        );

        if (CollectionUtils.isNotEmpty(nodes)) {
            // 每个运单只取最后一条离场记录
            offsiteNodeMap = nodes.stream()
                    .collect(Collectors.toMap(
                            KwtWaybillOrderNode::getWOrderId,
                            Function.identity(),
                            (existing, replacement) ->
                                    existing.getCreateTime().before(replacement.getCreateTime()) ? existing : replacement
                    ));
        }

        return offsiteNodeMap;
    }

    @NotNull

    private Set<Long> getLogOrderIds(WaybillOrderReq req, Set<Long> entIds,Long entId) {
        log.debug("开始查询物流订单ID，请求参数: {}, 企业ID: {}", JSON.toJSONString(req), entIds);
        Set<Long> logOrderIds = new HashSet<>();
        // 如果指定了物流订单ID，直接返回
        if (StringUtils.isNotBlank(req.getLogisticsOrderId())) {
            Long orderId = Long.parseLong(req.getLogisticsOrderId());
            log.debug("根据物流订单ID查询，ID: {}", orderId);
            logOrderIds.add(orderId);
            return logOrderIds;
        }
        entIds.add(entId);
        if (CollectionUtils.isNotEmpty(entIds)) {
            Set<Long> orderIdsByEnt = getLogOrderIdsByEntIds(entIds,req.getConsignorId(),req.getCarrierId(),entId);
            log.debug("根据企业ID查询到物流订单ID数量: {}", orderIdsByEnt.size());
            if (CollectionUtils.isNotEmpty(orderIdsByEnt)) {
                logOrderIds.addAll(orderIdsByEnt);
            }
        }

        // 如果指定了物流订单号，根据订单号查询
        if (StringUtils.isNotBlank(req.getLogisticsOrderNo())) {
            Set<Long> orderIdsByNo = getLogOrderIdsByNo(req.getLogisticsOrderNo());
            log.debug("根据物流订单号查询到ID数量: {}", orderIdsByNo.size());
            if (CollectionUtils.isNotEmpty(orderIdsByNo)) {
                intersectLogOrderIds(logOrderIds, orderIdsByNo);
                log.debug("物流订单号查询后，当前物流订单ID数量: {}", logOrderIds.size());
            } else {
                log.debug("根据物流订单号未查询到数据，返回空集合");
                return Collections.emptySet();
            }
        }
        // 如果指定了贸易订单号，根据贸易订单号查询
        if (StringUtils.isNotBlank(req.getTradeOrderNo())) {
            Set<Long> orderIdsByTradeOrderNo = getLogOrderIdsByTradeOrderNo(req.getTradeOrderNo());
            log.debug("根据贸易订单号查询到ID数量: {}", orderIdsByTradeOrderNo.size());
            if (CollectionUtils.isNotEmpty(orderIdsByTradeOrderNo)) {
                intersectLogOrderIds(logOrderIds, orderIdsByTradeOrderNo);
                log.debug("贸易订单号查询后，当前物流订单ID数量: {}", logOrderIds.size());
            } else {
                log.debug("根据贸易订单号未查询到数据，返回空集合");
                return Collections.emptySet();
            }
        }
        // 如果指定了结算方式，根据结算方式查询
        if (StringUtils.isNotBlank(req.getBillingMethod())) {
            Set<Long> orderIdsByBilling = getLogOrderIdsByBillingMethod(req.getBillingMethod());
            log.debug("根据结算方式查询到ID数量: {}", orderIdsByBilling.size());
            if (CollectionUtils.isNotEmpty(orderIdsByBilling)) {
                intersectLogOrderIds(logOrderIds, orderIdsByBilling);
                log.debug("结算方式查询后，当前物流订单ID数量: {}", logOrderIds.size());
            } else {
                log.debug("根据结算方式未查询到数据，返回空集合");
                return Collections.emptySet();
            }
        }

        // 如果指定了商品名称，根据商品名称查询
        if (StringUtils.isNotBlank(req.getGoodsName())) {
            Set<Long> orderIdsByGoods = getLogOrderIdsByGoodsName(req.getGoodsName());
            log.debug("根据商品名称查询到ID数量: {}", orderIdsByGoods.size());
            if (CollectionUtils.isNotEmpty(orderIdsByGoods)) {
                intersectLogOrderIds(logOrderIds, orderIdsByGoods);
                log.debug("商品名称查询后，当前物流订单ID数量: {}", logOrderIds.size());
            } else {
                log.debug("根据商品名称未查询到数据，返回空集合");
                return Collections.emptySet();
            }
        }

        log.debug("查询完成，最终物流订单ID数量: {}", logOrderIds.size());
        return logOrderIds;
    }

    /**
     * 获取企业ID集合
     */
    private Set<Long> getEnterpriseIds(WaybillOrderReq req) {
        Set<Long> entIds = new HashSet<>();


        if (StringUtils.isNotBlank(req.getConsignorId())) {
            entIds.add(Long.parseLong(req.getConsignorId()));
        }

        if (StringUtils.isNotBlank(req.getCarrierId())) {
            entIds.add(Long.parseLong(req.getCarrierId()));
        }

        return entIds;
    }

    /**
     * 获取当前登录用户的数据权限配置
     */
    private DataPermissionDTO fetchDataPermissionForCurrentUser() {
        try {
            DataPermissionFilterReqDto reqDto = new DataPermissionFilterReqDto();
            reqDto.setUserId(LoginUserHolder.getUserId());
            reqDto.setRoleId(LoginUserHolder.getCurrentRoleId());
            reqDto.setManager(LoginUserHolder.isManager());
            return dataPermissionFeignService.getDataPermissionFilter(reqDto);
        } catch (Exception e) {
            log.warn("获取数据权限失败，跳过运单列表数据权限过滤: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 根据数据权限过滤物流订单ID集合（{@link #findBillOrderListPage}、{@link #statisticsWaybillOrder} 等共用）。
     * <p>
     * 企业数据权限：按 {@code kwt_logistics_order_unit} 中托运/承运企业的 {@code ent_id} 是否落在角色可见企业范围内（与物流订单企业维度一致）。
     * 个人数据权限：关联贸易合同的 {@code salesman_id} 为当前用户；与企业在 {@link DataPermissionDTO} 下为 AND 组合。
     * </p>
     *
     * @param logOrderIds 待过滤的物流订单ID集合
     * @return 过滤后的物流订单ID集合
     */
    private Set<Long> applyDataPermissionFilterToLogOrderIds(Set<Long> logOrderIds) {
        log.debug("开始应用数据权限过滤，原始物流订单ID数量: {}", CollectionUtils.isEmpty(logOrderIds) ? 0 : logOrderIds.size());

        // 1. 获取当前用户的数据权限配置
        DataPermissionDTO perm = fetchDataPermissionForCurrentUser();

        // 如果无需过滤或权限配置为空，直接返回原始ID集合
        if (perm == null || !perm.needFilter()) {
            log.debug("无需进行数据权限过滤，直接返回原始ID集合");
            return logOrderIds;
        }

        // 如果原始ID集合为空，直接返回
        if (CollectionUtils.isEmpty(logOrderIds)) {
            log.debug("原始物流订单ID集合为空，无需过滤");
            return logOrderIds;
        }

        Set<Long> result = new HashSet<>(logOrderIds);

        // 2. 处理企业维度的数据权限
        if (!perm.isAllVisible()) {
            log.debug("非全量可见模式，开始执行企业维度权限过滤");

            // 如果可见企业ID列表为空，说明该企业维度下无权限，返回空集合
            if (CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
                log.warn("当前用户可见企业ID列表为空，过滤结果为空");
                return Sets.newHashSet();
            }

            // 查询可见企业ID关联的所有物流订单单位信息
            List<KwtLogisticsOrderUnit> units =
                    kwtLogisticsOrderUnitRepository.queryByEntIds(new HashSet<>(perm.getVisibleEntIds()));

            // 提取这些单位关联的物流订单ID
            Set<Long> entScopeLogOrderIds = units.stream()
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            log.debug("企业维度过滤：可见企业关联的物流订单ID数量: {}", entScopeLogOrderIds.size());

            // 取交集：只保留既在原始列表中，又在可见企业关联列表中的ID
            result.retainAll(entScopeLogOrderIds);
            log.debug("企业维度过滤后剩余ID数量: {}", result.size());
        }

        // 如果经过企业维度过滤后结果为空，直接返回
        if (CollectionUtils.isEmpty(result)) {
            log.debug("企业维度过滤后结果为空，提前返回");
            return result;
        }

        // 3. 处理个人维度的数据权限
        if (!perm.isPersonalDataEnabled()) {
            log.debug("未启用个人数据权限，返回当前过滤结果");
            return result;
        }

        log.debug("启用个人数据权限，开始执行销售员维度过滤");
        return filterLogOrderIdsByTradeContractSalesman(result, perm);
    }

    /**
     * 个人数据权限过滤：仅保留关联贸易合同中销售员为当前用户的物流订单。
     * <p>
     * 逻辑链路：物流订单 -> 贸易订单ID -> 贸易合同ID -> 合同基本信息(销售员ID)
     * </p>
     *
     * @param logOrderIds 待过滤的物流订单ID集合
     * @param perm        数据权限配置对象
     * @return 过滤后的物流订单ID集合
     */
    private Set<Long> filterLogOrderIdsByTradeContractSalesman(Set<Long> logOrderIds, DataPermissionDTO perm) {
        Long currentUserId = perm.getUserId();
        log.debug("开始个人数据权限过滤，当前用户ID: {}, 待过滤物流订单ID数量: {}", currentUserId, logOrderIds.size());

        // 校验用户ID
        if (currentUserId == null) {
            log.warn("个人数据权限启用但用户ID为空，返回空集合");
            return Sets.newHashSet();
        }

        // 1. 查询物流订单详情，获取关联的贸易订单ID
        List<KwtLogisticsOrder> orders = logisticsOrderRepository.queryByLogOrderIds(logOrderIds);
        if (CollectionUtils.isEmpty(orders)) {
            log.debug("未查询到对应的物流订单详情，返回空集合");
            return Sets.newHashSet();
        }

        // 提取所有非空的贸易订单ID
        Set<Long> tradeIds = orders.stream()
                .map(KwtLogisticsOrder::getTOrderId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(tradeIds)) {
            log.debug("物流订单中未关联有效的贸易订单ID，返回空集合");
            return Sets.newHashSet();
        }
        log.debug("提取到贸易订单ID数量: {}", tradeIds.size());

        // 2. 查询贸易订单与贸易合同的关联关系
        List<TradeOrderContractVo> contractLinks = tradeOrderInfoService.queryTradeOrderIds(tradeIds);
        Map<Long, Long> tradeIdToContractId = new HashMap<>();
        if (CollectionUtils.isNotEmpty(contractLinks)) {
            for (TradeOrderContractVo link : contractLinks) {
                if (link.getTOrderId() == null || link.getContractId() == null) {
                    continue;
                }
                // 使用 putIfAbsent 确保一个贸易订单只映射一个合同ID（通常是一对一）
                tradeIdToContractId.putIfAbsent(link.getTOrderId(), link.getContractId());
            }
        }
        log.debug("建立贸易订单到合同ID的映射，映射数量: {}", tradeIdToContractId.size());

        // 3. 批量查询合同基本信息（包含销售员ID）
        List<Long> contractIdList = tradeIdToContractId.values().stream().distinct().collect(Collectors.toList());
        Map<Long, ContractCommonInfoResDto> contractMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(contractIdList)) {
            contractMap = remoteContractService.queryContractBaseInfo(contractIdList);
            log.debug("批量查询合同基本信息完成，获取合同数量: {}", contractMap.size());
        }

        // 4. 筛选出销售员为当前用户的贸易订单ID
        Set<Long> allowedTradeIds = new HashSet<>();
        for (Long tid : tradeIds) {
            Long cid = tradeIdToContractId.get(tid);
            if (cid == null) {
                continue;
            }
            ContractCommonInfoResDto contractInfo = contractMap.get(cid);
            if (contractInfo == null) {
                continue;
            }
            // 判断合同的销售员是否为当前用户
            if (currentUserId.equals(contractInfo.getSalesmanId())) {
                allowedTradeIds.add(tid);
            }
        }
        log.debug("个人权限过滤：当前用户作为销售员的贸易订单ID数量: {}", allowedTradeIds.size());

        // 5. 根据允许的贸易订单ID，反查并返回对应的物流订单ID
        Set<Long> finalResult = orders.stream()
                .filter(order -> order.getTOrderId() != null && allowedTradeIds.contains(order.getTOrderId()))
                .map(KwtLogisticsOrder::getId)
                .collect(Collectors.toSet());

        log.debug("个人数据权限过滤完成，最终保留物流订单ID数量: {}", finalResult.size());
        return finalResult;
    }

    /**
     * 根据企业ID集合获取物流订单ID集合
     */
    private Set<Long> getLogOrderIdsByEntIds(Set<Long> entIds,String consignorId,String carrierId,Long entId) {
        List<KwtLogisticsOrderUnit> unitList = kwtLogisticsOrderUnitRepository.queryByEntIds(entIds);
        if (CollectionUtils.isEmpty(unitList)) {
            return Collections.emptySet();
        }
        Set<Long> logOrderIds = unitList.stream().filter(x->Objects.equals(x.getEntId(),entId))
                .map(KwtLogisticsOrderUnit::getLOrderId).collect(Collectors.toSet());


        if (StringUtils.isNotBlank(consignorId)){
            Set<Long> finalLogOrderIds = logOrderIds;
            logOrderIds = unitList.stream()
                    .filter(x->Objects.equals(x.getEntId(),Long.parseLong(consignorId)) &&  finalLogOrderIds.contains(x.getLOrderId()))
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .collect(Collectors.toSet());
        }
        if (StringUtils.isNotBlank(carrierId)){
            Set<Long> finalLogOrderIds1 = logOrderIds;
            logOrderIds =  unitList.stream()
                    .filter(x->Objects.equals(x.getEntId(),Long.parseLong(carrierId)) && finalLogOrderIds1.contains(x.getLOrderId()))
                    .map(KwtLogisticsOrderUnit::getLOrderId)
                    .collect(Collectors.toSet());
        }
        return logOrderIds;

    }

    /**
     * 根据物流订单号获取物流订单ID集合
     */
    private Set<Long> getLogOrderIdsByNo(String logisticsOrderNo) {
        KwtLogisticsOrder logisticsOrder = logisticsOrderRepository.queryByLogisticsOrderNo(logisticsOrderNo);
        if (Objects.isNull(logisticsOrder)) {
            return Collections.emptySet();
        }

        Set<Long> orderIds = new HashSet<>();
        orderIds.add(logisticsOrder.getId());
        return orderIds;
    }
    /**
     * 根据贸易订单号获取物流订单ID集合
     */
    private Set<Long> getLogOrderIdsByTradeOrderNo(String tradeOrderNo) {
        List<KwtLogisticsOrder> logisticsOrders = logisticsOrderRepository.queryTradeOrderNo(tradeOrderNo);
        if (CollectionUtils.isEmpty(logisticsOrders)) {
            return Collections.emptySet();
        }

        return logisticsOrders.stream()
                .map(KwtLogisticsOrder::getId)
                .collect(Collectors.toSet());
    }
    /**
     * 根据结算方式获取物流订单ID集合
     */
    private Set<Long> getLogOrderIdsByBillingMethod(String billingMethod) {
        List<KwtLogisticsOrder> logisticsOrders = logisticsOrderRepository.queryByBillMethod(billingMethod);
        if (CollectionUtils.isEmpty(logisticsOrders)) {
            return Collections.emptySet();
        }

        return logisticsOrders.stream()
                .map(KwtLogisticsOrder::getId)
                .collect(Collectors.toSet());
    }

    /**
     * 根据商品名称获取物流订单ID集合
     */
    private Set<Long> getLogOrderIdsByGoodsName(String goodsName) {
        List<KwpGoods> goods = goodsInfoService.findGoodsByGoodsName(goodsName);
        if (CollectionUtils.isEmpty(goods)) {
            return Collections.emptySet();
        }

        Set<Long> goodsIds = goods.stream()
                .map(KwpGoods::getId)
                .collect(Collectors.toSet());

        List<KwtLogisticsOrderGoods> logisticsOrderGoods = kwtLogisticsOrderGoodsRepository.queryByGoodsIds(goodsIds);
        if (CollectionUtils.isEmpty(logisticsOrderGoods)) {
            return Collections.emptySet();
        }

        return logisticsOrderGoods.stream()
                .map(KwtLogisticsOrderGoods::getLOrderId)
                .collect(Collectors.toSet());
    }


    /**
     * 对物流订单ID集合进行交集操作
     * 如果原集合为空，则添加新集合的所有元素
     * 如果原集合不为空，则保留原集合与新集合的交集
     *
     * @param logOrderIds 原物流订单ID集合
     * @param newOrderIds 新物流订单ID集合
     */
    private void intersectLogOrderIds(Set<Long> logOrderIds, Set<Long> newOrderIds) {
        if (logOrderIds.isEmpty()) {
            logOrderIds.addAll(newOrderIds);
        } else {
            logOrderIds.retainAll(newOrderIds);
        }
    }

    @NotNull
    private Set<Long> getBillOrderIds(WaybillOrderReq req) {
        Set<Long> billOrderIds = Sets.newHashSet();
        KwtWaybillOrder order = getKwtWaybillOrder(req);
        boolean b = Stream.of(req.getWaybillNo(), req.getTruckNo(), req.getDriverName(), req.getPhone()).anyMatch(StringUtils::isNotBlank);
        if (b){
            List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryByCondition(order);
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(waybillOrders)){
                billOrderIds.addAll(waybillOrders.stream()
                        .map(KwtWaybillOrder::getId)
                        .collect(Collectors.toSet()));
            }
        }
        if (org.apache.commons.lang3.StringUtils.isNoneBlank(req.getLoadStartTime(),req.getLoadEndTime())){
            Date loadStartTime = DateUtils.formatDate(req.getLoadStartTime());
            Date loadEndTime = DateUtils.formatDate(req.getLoadEndTime());
            List<KwtWaybillOrderTicket> tickets = kwtWaybillOrderTicketRepository.queryByOperateTime(loadStartTime,
                    loadEndTime,1);
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty( tickets)){
                billOrderIds.addAll(tickets.stream()
                        .map(KwtWaybillOrderTicket::getWOrderId)
                        .collect(Collectors.toSet()));
            }
        }

        if (org.apache.commons.lang3.StringUtils.isNoneBlank(req.getUnloadStartTime(),req.getUnloadEndTime())){
            Date unloadStartTime = DateUtils.formatDate(req.getUnloadStartTime());
            Date unloadEndTime = DateUtils.formatDate(req.getUnloadEndTime());
            List<KwtWaybillOrderTicket> tickets = kwtWaybillOrderTicketRepository.queryByOperateTime(unloadStartTime,
                    unloadEndTime,2);
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty( tickets)){
                billOrderIds.addAll(tickets.stream()
                        .map(KwtWaybillOrderTicket::getWOrderId)
                        .collect(Collectors.toSet()));
            }
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getUnloadStartTime()) &&
                org.apache.commons.lang3.StringUtils.isNotBlank(req.getUnloadEndTime())) {
            //查询节点数据 2026-01-04 09:01:21
            Date startDate = getStartDate(req.getUnloadStartTime());
            Date endDate = getEndDate(req.getUnloadEndTime());
            List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.queryByOperateTime(startDate, endDate,CarWaybillV1Enum.COMPLETION_LOADING.getCode());
            Set<Long> billOrderIds2 = Optional.ofNullable(nodes)
                    .orElse(List.of()).stream()
                    .map(KwtWaybillOrderNode::getWOrderId)
                    .collect(Collectors.toSet());
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty( billOrderIds2)){
                billOrderIds.addAll(billOrderIds2);
            }
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getLoadStartTime()) &&
                org.apache.commons.lang3.StringUtils.isNotBlank(req.getLoadEndTime())) {
            //查询节点数据 2026-01-04 09:01:21
            Date startDate = getStartDate(req.getLoadStartTime());
            Date endDate = getEndDate(req.getLoadEndTime());
            List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.queryByOperateTime(startDate, endDate,CarWaybillV1Enum.EXIT_COMPLETED.getCode());
            Set<Long> billOrderIds2 = Optional.ofNullable(nodes)
                    .orElse(List.of()).stream()
                    .map(KwtWaybillOrderNode::getWOrderId)
                    .collect(Collectors.toSet());
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty( billOrderIds2)){
                billOrderIds.addAll(billOrderIds2);
            }
        }
        return billOrderIds;
    }

    private static Date getStartDate(String date) {
        Date startDate;
        if (org.apache.commons.lang3.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 (org.apache.commons.lang3.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;
    }

    @NotNull
    private static WaybillOrderResp getWaybillOrderResp(KwtWaybillOrderSubtask record, Map<Long, KwtWaybillOrder> finalWaybillOrderIdAndBillOrderMap,
                                                        Map<String, KwtLogisticsOrderUnit> finalLogOrderIdUnitTypeKeyAndUnitMap,
                                                        Map<Long, KwtLogisticsOrderGoods> finalLogOrderIdAndGoodsIdMap,
                                                        Map<Long, KwpGoods> kwpGoodsMap,
                                                        Map<String, KwtWaybillOrderAddress> finalSubOrderIdAddressTypeKeyAndAddressMap,
                                                        Map<String, KwtWaybillOrderNode> waybillOrderNodeMap,
                                                        Map<Long, KwtLogisticsOrder> finalLogIdAndOrderMap,
                                                        Map<String, Map<String, String>> dictValueAndDictResDtoMap,
                                                        Map<Long, KwtWaybillOrderNode> wOrderIdAndOffsiteNodeMap,
                                                        Map<Long, RTruckVo> carAxisMap,
                                                        Map<String, KwtWaybillOrderTicket> ticketMap,
                                                        Map<Long, KwtLogisticsOrder> logisticsOrderMap,
                                                        Map<Long, TradeOrderContractVo> tradeOrderContractVoMap,
                                                        Map<String, TradeContractGoodsDto> orderContracGoodstoMap) {
        WaybillOrderResp waybillOrderResp = new WaybillOrderResp();
        KwtWaybillOrder billOrder = finalWaybillOrderIdAndBillOrderMap.getOrDefault(record.getWOrderId(),
                new KwtWaybillOrder());
        waybillOrderResp.setWaybillOrderId(String.valueOf(billOrder.getId()));
        waybillOrderResp.setWaybillOrderNo(billOrder.getWOrderNo());
        waybillOrderResp.setLogisticsOrderId(String.valueOf(record.getLOrderId()));
        KwtLogisticsOrder order = finalLogIdAndOrderMap.getOrDefault(record.getLOrderId(), new KwtLogisticsOrder());
        waybillOrderResp.setLogisticsOrderNo(order.getLOrderNo());
        KwtLogisticsOrderUnit consignUnit = finalLogOrderIdUnitTypeKeyAndUnitMap.getOrDefault(record.getLOrderId() + "-" + NumberConstant.ONE,
                new KwtLogisticsOrderUnit());
        waybillOrderResp.setConsignUnitId(String.valueOf(consignUnit.getEntId()));
        waybillOrderResp.setConsignUnitName(consignUnit.getFirmName());
        KwtLogisticsOrderUnit carriageUnit =
                finalLogOrderIdUnitTypeKeyAndUnitMap.getOrDefault(record.getLOrderId() + "-" + NumberConstant.TWO,
                new KwtLogisticsOrderUnit());
        waybillOrderResp.setCarriageUnitId(String.valueOf(carriageUnit.getEntId()));
        waybillOrderResp.setCarriageUnitName(carriageUnit.getFirmName());
        waybillOrderResp.setTruckNo(billOrder.getTruckNo());
        waybillOrderResp.setDriverName(billOrder.getDriverName());
        waybillOrderResp.setDriverPhone(billOrder.getDriverPhone());
        //轴数
        RTruckVo rTruckVo = carAxisMap.getOrDefault(billOrder.getTruckId(), new RTruckVo());
        waybillOrderResp.setCarAxisName(rTruckVo.getCarAxis());

        //皮重、毛重
        KwtWaybillOrderTicket tareAmountTicket = ticketMap.getOrDefault(billOrder.getId() + "-" + AddressTypeEnum.SHIPMENT.getCode(), new KwtWaybillOrderTicket());
        waybillOrderResp.setTareAmount(tareAmountTicket.getTareAmount());
        waybillOrderResp.setGrossAmount(tareAmountTicket.getGrossAmount());

        Long lOrderId = record.getLOrderId();

        KwtLogisticsOrderGoods goods = finalLogOrderIdAndGoodsIdMap.getOrDefault(lOrderId,
                new KwtLogisticsOrderGoods());
        KwpGoods kwpGoods = kwpGoodsMap.get(goods.getGoodsId());
        if (Objects.nonNull(kwpGoods)){

            Map<String, String> goodsTypeMap= dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), new HashMap<>());
            Map<String, String> goodsSpecMap= dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.GOODS_SPEC.getType(), new HashMap<>());
            waybillOrderResp.setGoodsName(kwpGoods.getName()+"/"+goodsTypeMap.getOrDefault(kwpGoods.getGoodsType(),"")+"/"+goodsSpecMap.getOrDefault(kwpGoods.getSpec(), ""));
        }
        waybillOrderResp.setTaskNum((Objects.nonNull(record.getEntrustAmount()) ?
                record.getEntrustAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00")+record.getUnit());
        waybillOrderResp.setLoadingNetWeight((Objects.nonNull(record.getLoadAmount()) ?
                record.getLoadAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00") +record.getUnit());
        KwtWaybillOrderAddress loadingAdd = finalSubOrderIdAddressTypeKeyAndAddressMap.getOrDefault(record.getId() + "-" + AddressTypeEnum.SHIPMENT.getCode(),
                new KwtWaybillOrderAddress());
        waybillOrderResp.setLoadingAddress(loadingAdd.getCityName()+loadingAdd.getDetailAddress());
        waybillOrderResp.setUnloadingNetWeight((Objects.nonNull(record.getUnloadAmount()) ?
                record.getUnloadAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00")+record.getUnit());
        KwtWaybillOrderAddress unloadingAdd =
                finalSubOrderIdAddressTypeKeyAndAddressMap.getOrDefault(record.getId() + "-" + AddressTypeEnum.TAKE.getCode(),
                new KwtWaybillOrderAddress());
        waybillOrderResp.setUnloadingAddress(unloadingAdd.getCityName()+unloadingAdd.getDetailAddress());

        KwtWaybillOrderNode loadTrack =
                waybillOrderNodeMap.getOrDefault(record.getWOrderId() + "-" + CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
                new KwtWaybillOrderNode());

        KwtWaybillOrderNode accept =
                waybillOrderNodeMap.getOrDefault(record.getWOrderId() + "-" + CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
                        new KwtWaybillOrderNode());

        waybillOrderResp.setAcceptTime(DateUtils.format(accept.getCreateTime(),DateUtils.DATE_TIME_PATTERN));
        KwtWaybillOrderNode unloadTrack =
                waybillOrderNodeMap.getOrDefault(record.getWOrderId() + "-" + CarWaybillV1Enum.COMPLETION_LOADING.getCode(),
                        new KwtWaybillOrderNode());
        waybillOrderResp.setLoadingTime(DateUtils.format(loadTrack.getCreateTime(),DateUtils.DATE_TIME_PATTERN));

        // 从节点表中获取离场时间
        KwtWaybillOrderNode offsiteNode = wOrderIdAndOffsiteNodeMap.get(record.getWOrderId());
        if (offsiteNode != null) {
            waybillOrderResp.setOffsiteTime(DateUtils.format(offsiteNode.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
        }

        waybillOrderResp.setUnloadingTime(DateUtils.format(unloadTrack.getCreateTime(),DateUtils.DATE_TIME_PATTERN));
        if (Objects.equals(record.getStatus(), CarWaybillV1Enum.COMPLETED.getCode())){
            waybillOrderResp.setCompleteTime(DateUtils.format(record.getUpdateTime(),DateUtils.DATE_TIME_PATTERN));
        }

        waybillOrderResp.setStatus(String.valueOf(record.getStatus()));
        waybillOrderResp.setStatusDesc(CarWaybillV1Enum.geDesc(record.getStatus()));
        KwtLogisticsOrder logOrder = logisticsOrderMap.getOrDefault(lOrderId, new KwtLogisticsOrder());
        //计费方式
        waybillOrderResp.setPriceType(String.valueOf(logOrder.getBillingMode()));
        waybillOrderResp.setPriceTypeDesc(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), logOrder.getBillingMode()));

        KwtLogisticsOrderGoods kwtLogisticsOrderGoods = finalLogOrderIdAndGoodsIdMap.getOrDefault(lOrderId, new KwtLogisticsOrderGoods());
        TradeOrderContractVo tradeOrderContractVo = tradeOrderContractVoMap.getOrDefault(logOrder.getTOrderId(), new TradeOrderContractVo());
        TradeContractGoodsDto contractGoodsDto = orderContracGoodstoMap.getOrDefault(tradeOrderContractVo.getContractId()+"-"+kwtLogisticsOrderGoods.getGoodsId(), new TradeContractGoodsDto());
        if (Objects.equals(logOrder.getOrderType(),1)){
            log.info("原矿转运，计算运费{}", record.getWOrderNo());
            BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(record.getUnloadAmount()) ?
                    logOrder.getPrice().multiply(record.getUnloadAmount()) : BigDecimal.ZERO;
            BigDecimal actualGoodsPrice = Objects.nonNull(contractGoodsDto.getPrice()) && Objects.nonNull(record.getUnloadAmount()) ?
                    contractGoodsDto.getPrice().multiply(record.getUnloadAmount()) : BigDecimal.ZERO;
            waybillOrderResp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            waybillOrderResp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            waybillOrderResp.setUnloadingNetWeight((Objects.nonNull(record.getUnloadAmount()) ?
                    record.getUnloadAmount().setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00")+"吨");
        } else {
            log.info("普通订单，计算运费{}", record.getWOrderNo());
            if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_1.getValue())){
                BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(record.getLoadAmount()) ?
                        logOrder.getPrice().multiply(record.getLoadAmount()) : BigDecimal.ZERO;
                BigDecimal actualGoodsPrice = Objects.nonNull(contractGoodsDto.getPrice()) && Objects.nonNull(record.getLoadAmount()) ?
                        contractGoodsDto.getPrice().multiply(record.getLoadAmount()) : BigDecimal.ZERO;
                waybillOrderResp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
                waybillOrderResp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            }else if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_2.getValue())){
                BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(record.getUnloadAmount()) ?
                        logOrder.getPrice().multiply(record.getUnloadAmount()) : BigDecimal.ZERO;
                BigDecimal actualGoodsPrice = Objects.nonNull(contractGoodsDto.getPrice()) && Objects.nonNull(record.getUnloadAmount()) ?
                        contractGoodsDto.getPrice().multiply(record.getUnloadAmount()) : BigDecimal.ZERO;
                waybillOrderResp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
                waybillOrderResp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
            }
        }


        return waybillOrderResp;
    }

    @NotNull
    private static KwtWaybillOrder getKwtWaybillOrder(WaybillOrderReq req) {
        KwtWaybillOrder order = new KwtWaybillOrder();
        order.setWOrderNo(req.getWaybillNo());
        order.setTruckNo(req.getTruckNo());
        order.setDriverName(req.getDriverName());
        order.setDriverPhone(req.getPhone());
        return order;
    }

    @Resource(name = "traceTaskExecutor")
    private Executor traceTaskExecutor;


    public WaybillOrderDetailResp queryBillOrderDetail(WaybillOrderRequest req) {
        log.info("查询运单详情请求：{}", JSON.toJSONString(req));
        Long orderId = req.getOrderId();

        if (Objects.isNull(orderId)) {
            throw new BusinessException("运单ID不能为空");
        }

        // 获取基础数据
        KwtWaybillOrder billOrder = getBillOrder(orderId);
        KwtWaybillOrderSubtask subtask = getSubtask(billOrder.getId());
        KwtLogisticsOrder logOrder = getLogisticsOrder(subtask.getLOrderId());

        // 并行执行多个不相互依赖的查询
        log.debug("开始并行查询相关数据，主运单ID: {}", billOrder.getId());
        CompletableFuture<RTruckVo> truckFuture = CompletableFuture.supplyAsync(() ->
                remoteFleetService.findTruck(billOrder.getTruckId())).exceptionally(ex -> {
            log.error("异步任务执行失败", ex);
            throw new BusinessException("查询车型信息失败");
        });;

        CompletableFuture<RFleetVo> fleetFuture = CompletableFuture.supplyAsync(() ->
                getFleetInfo(billOrder.getTruckId()),traceTaskExecutor);

        CompletableFuture<List<KwtLogisticsOrderAddress>> addressFuture = CompletableFuture.supplyAsync(() ->
                kwtLogisticsOrderAddressRepository.queryByLogOrderId(subtask.getLOrderId()),traceTaskExecutor);

        CompletableFuture<List<KwtWaybillOrderTicket>> ticketFuture = CompletableFuture.supplyAsync(() ->
                kwtWaybillOrderTicketRepository.queryByWOrderId(req.getOrderId()),traceTaskExecutor);

        CompletableFuture<UserCacheResDto> userFuture = CompletableFuture.supplyAsync(() ->
                getUserInfo(subtask.getUnloadOperator()),traceTaskExecutor).exceptionally(ex -> {
            log.error("异步任务执行失败", ex);
            throw new BusinessException("查询用户信息失败");
        });

        CompletableFuture<KwtLogisticsOrderGoods> goodsFuture = CompletableFuture.supplyAsync(() ->
                kwtLogisticsOrderGoodsRepository.queryByLogOrderId(logOrder.getId()),traceTaskExecutor);

        CompletableFuture<OrderDetailVo> orderDetailFuture;
        //1.正常流程
        if (!Objects.equals(1, logOrder.getOrderType())) {
            orderDetailFuture = CompletableFuture.supplyAsync(() ->
                    getOrderDetail(logOrder.getTOrderId()),traceTaskExecutor).exceptionally(ex -> {
                log.error("异步任务执行失败", ex);
                throw new BusinessException("查询订单详情失败");
            });
        } else {
            //2.原矿运输
            orderDetailFuture = CompletableFuture.completedFuture(null);
        }

        CompletableFuture<List<KwtLogisticsOrderUnit>> unitFuture = CompletableFuture.supplyAsync(() ->
                kwtLogisticsOrderUnitRepository.queryByLOrderId(logOrder.getId()),traceTaskExecutor);

        CompletableFuture<List<KwtWaybillOrderNode>> nodeFuture = CompletableFuture.supplyAsync(() ->
                kwtWaybillOrderNodeRepository.queryNodesByOrderId(billOrder.getId(), subtask.getId()),traceTaskExecutor);

        CompletableFuture<List<KwtWaybillOrderSubtask>> waybillSubtaskFuture = CompletableFuture.supplyAsync(() ->
                kwtWaybillOrderSubtaskRepository.queryByLogId(logOrder.getId()),traceTaskExecutor);


        CompletableFuture<TradeContractGoodsDto> contractFuture;
        //1.正常流程
        if (!Objects.equals(1, logOrder.getOrderType())) {
            contractFuture =
                    goodsFuture.thenCompose(goods -> {
                        Long goodsId = Optional.ofNullable(goods)
                                .map(KwtLogisticsOrderGoods::getGoodsId)
                                .orElse(null);
                        log.debug("开始查询合同信息，贸易订单ID: {}, 商品ID: {}", logOrder.getTOrderId(), goodsId);

                        return CompletableFuture
                                .supplyAsync(
                                        () -> tradeOrderInfoService.queryByContractByTradeOrderId(logOrder.getTOrderId()), traceTaskExecutor)
                                .thenCompose(tradeOrderInfo -> {
                                    log.debug("贸易订单合同信息查询完成，合同ID: {}", tradeOrderInfo.getContractId());
                                    return CompletableFuture.supplyAsync(
                                            () -> remoteContractService.queryContractGoodsByContractId(tradeOrderInfo.getContractId(), goodsId), traceTaskExecutor
                                    );
                                });
                    }).exceptionally(ex -> {
                        log.error("异步任务执行失败", ex);
                        throw new BusinessException("查询合同信息失败");
                    });
        } else {
            //2.原矿运输
            contractFuture = CompletableFuture.completedFuture(null);
        }

        // 等待所有并行查询完成
        log.debug("等待所有并行查询完成");
        try {
            CompletableFuture.allOf(
                    truckFuture, fleetFuture, addressFuture, ticketFuture, userFuture,
                    goodsFuture, orderDetailFuture, unitFuture, nodeFuture, waybillSubtaskFuture,
                    contractFuture
            ).get(30, TimeUnit.SECONDS);

        } catch (Exception e) {
            // 超时会抛出 TimeoutException
            // 任意任务失败会抛出 ExecutionException
            // 中断会抛出 InterruptedException
            throw new RuntimeException("批量异步任务执行失败/超时", e);
        }
        log.debug("所有并行查询完成");

        // 获取查询结果
        return buildWaybillOrderDetailResp(billOrder, subtask, logOrder, truckFuture.join(),
                fleetFuture.join(), addressFuture.join(), ticketFuture.join(), userFuture.join(),
                goodsFuture.join(), orderDetailFuture.join(), unitFuture.join(),
                nodeFuture.join(), waybillSubtaskFuture.join(),contractFuture.join());
    }

    /**
     * 获取主运单信息
     */
    private KwtWaybillOrder getBillOrder(Long orderId) {
        log.debug("开始查询主运单信息，运单ID: {}", orderId);
        KwtWaybillOrder billOrder = kwtWaybillOrderRepository.queryByBillOrderId(orderId);
        if (Objects.isNull(billOrder)) {
            log.warn("运单信息不存在，运单ID: {}", orderId);
            throw new BusinessException("运单信息不存在");
        }
        log.debug("主运单查询完成，运单ID: {}", billOrder.getId());
        return billOrder;
    }

    /**
     * 获取子运单信息
     */
    private KwtWaybillOrderSubtask getSubtask(Long billOrderId) {
        log.debug("开始查询子运单信息，主运单ID: {}", billOrderId);
        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.queryByBillOrderId(billOrderId);
        if (Objects.isNull(subtask)) {
            log.warn("子运单信息不存在，主运单ID: {}", billOrderId);
            throw new BusinessException("子运单信息不存在");
        }
        log.debug("子运单查询完成，子运单ID: {}", subtask.getId());
        return subtask;
    }

    /**
     * 获取物流订单信息
     */
    private KwtLogisticsOrder getLogisticsOrder(Long logOrderId) {
        log.debug("开始查询物流订单信息，物流订单ID: {}", logOrderId);
        KwtLogisticsOrder logOrder = kwtLogisticsOrderRepository.queryByLogisticsOrderId(logOrderId);
        if (Objects.isNull(logOrder)) {
            log.warn("物流信息不存在，物流订单ID: {}", logOrderId);
            throw new BusinessException("物流信息不存在");
        }
        log.debug("物流订单查询完成，物流订单ID: {}", logOrder.getId());
        return logOrder;
    }

    /**
     * 获取车队信息
     */
    private RFleetVo getFleetInfo(Long truckId) {
        try {
            log.debug("查询车队信息，车辆ID: {}", truckId);
            RFleetVo fleet = remoteFleetService.findFleetByTruckId(truckId);
            log.debug("查询车队信息完成，车队信息: {}", JSON.toJSONString(fleet));
            return fleet;
        } catch (Exception e) {
            log.error("查询车队信息异常，车辆ID: {}, 异常信息: {}", truckId, e.getMessage());
            return null;
        }
    }

    /**
     * 获取用户信息
     */
    private UserCacheResDto getUserInfo(Long unloadOperator) {
        if (Objects.nonNull(unloadOperator)) {
            log.debug("查询卸货操作员信息，用户ID: {}", unloadOperator);
            return remoteSystemService.queryUserCacheById(unloadOperator);
        }
        return null;
    }

    /**
     * 获取贸易订单详情
     */
    private OrderDetailVo getOrderDetail(Long tOrderId) {
        if (Objects.nonNull(tOrderId)) {
            log.debug("查询贸易订单详情，贸易订单ID: {}", tOrderId);
            return tradeOrderInfoService.queryByTradeOrderId(tOrderId);
        }
        return null;
    }

    /**
     * 构建运单详情响应对象
     */
    private WaybillOrderDetailResp buildWaybillOrderDetailResp(KwtWaybillOrder billOrder,
                                                              KwtWaybillOrderSubtask subtask,
                                                              KwtLogisticsOrder logOrder,
                                                              RTruckVo truck,
                                                              RFleetVo fleet,
                                                              List<KwtLogisticsOrderAddress> kwtWaybillOrderAddresses,
                                                              List<KwtWaybillOrderTicket> orderTicketList,
                                                              UserCacheResDto userCacheResDto,
                                                              KwtLogisticsOrderGoods goods,
                                                              OrderDetailVo orderDetailVo,
                                                              List<KwtLogisticsOrderUnit> unitList,
                                                              List<KwtWaybillOrderNode> kwtWaybillOrderNodes,
                                                              List<KwtWaybillOrderSubtask> waybillOrderSubtasks,
                                                               TradeContractGoodsDto contractGoodsDto) {
        log.debug("开始处理查询结果，主运单ID: {}, 子运单ID: {}", billOrder.getId(), subtask.getId());

        if (CollectionUtils.isEmpty(orderTicketList)) {
            log.warn("当前车辆无物流运单装卸货信息，运单ID: {}", billOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_TICKET, "当前车辆无物流运单装卸货信息");
        }

        // 处理商品信息
        KwpGoods kwpGoods = getKwpGoods(goods);

        // 处理合同采购单位
        List<TradeContractUnitDto> tradeContractUnitDtos = getTradeContractUnits(orderDetailVo, logOrder);

        // 处理地址信息
        Map<String, KwtLogisticsOrderAddress> keyAndAddressMap = processAddresses(kwtWaybillOrderAddresses);
        log.debug("地址信息处理完成，地址数量: {}", keyAndAddressMap.size());

        // 处理企业信息
        Map<String, KwtLogisticsOrderUnit> logisticsOrderUnitMap = processUnits(unitList);
        log.debug("企业信息处理完成，企业数量: {}", logisticsOrderUnitMap.size());

        // 处理轨迹信息
        List<KwtWaybillOrderNode> nodeList = processNodes(kwtWaybillOrderNodes);
        log.debug("轨迹信息处理完成，称重记录数量: {}", nodeList.size());

        // 处理关联运单
        List<KwtWaybillOrder> billOrders = processBillOrders(waybillOrderSubtasks);
        log.debug("关联运单处理完成，关联运单数量: {}", billOrders.size());

        // 处理装卸货信息
        Map<String, KwtWaybillOrderTicket> ticketMap = processTickets(orderTicketList);
        log.debug("装卸货票据信息处理完成，票据数量: {}", ticketMap.size());

        // 查询字典数据
        log.debug("查询字典数据");
        Map<String, Map<String, String>> dictValueAndDictResDtoMap = remoteSystemService.queryDictByType(
                Arrays.asList(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.GOODS_SPEC.getType()));

        log.info("运单详情查询完成，运单ID: {}", billOrder.getId());
        return getWaybillOrderDetailResp(subtask, billOrder, logOrder, truck, fleet, goods,
                keyAndAddressMap, kwpGoods, logisticsOrderUnitMap, nodeList, userCacheResDto,
                billOrders, ticketMap, dictValueAndDictResDtoMap, tradeContractUnitDtos,contractGoodsDto);
    }

    /**
     * 获取商品信息
     */
    private KwpGoods getKwpGoods(KwtLogisticsOrderGoods goods) {
        if (Objects.nonNull(goods) && Objects.nonNull(goods.getGoodsId())) {
            log.debug("查询商品详情，商品ID: {}", goods.getGoodsId());
            return goodsInfoService.getGoodsById(goods.getGoodsId());
        }
        return null;
    }

    /**
     * 获取合同采购单位信息
     */
    private List<TradeContractUnitDto> getTradeContractUnits(OrderDetailVo orderDetailVo, KwtLogisticsOrder logOrder) {
        //原矿运输没有贸易订单
        if (Objects.equals(1, logOrder.getOrderType())) {
            return Lists.newArrayList();
        }
        if (Objects.nonNull(orderDetailVo) && Objects.nonNull(orderDetailVo.getContractInfo())
            && Objects.nonNull(orderDetailVo.getContractInfo().getContractId())) {
            log.debug("查询合同单位信息，合同ID: {}", orderDetailVo.getContractInfo().getContractId());
            return remoteContractService.queryContractUnitByContractId(
                    orderDetailVo.getContractInfo().getContractId());
        }
        return Lists.newArrayList();
    }

    /**
     * 处理地址信息
     */
    private Map<String, KwtLogisticsOrderAddress> processAddresses(List<KwtLogisticsOrderAddress> addresses) {
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(addresses)) {
            return addresses.stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(
                            x -> x.getLOrderId() + "-" + x.getAddressType(),
                            Function.identity(),
                            (x, y) -> x));
        }
        return Maps.newHashMap();
    }

    /**
     * 处理企业信息
     */
    private Map<String, KwtLogisticsOrderUnit> processUnits(List<KwtLogisticsOrderUnit> unitList) {
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(unitList)) {
            return unitList.stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(
                            x -> x.getLOrderId() + "-" + x.getUnitType(),
                            Function.identity(),
                            (x, y) -> x));
        }
        return Maps.newHashMap();
    }

    /**
     * 处理轨迹信息
     */
    private List<KwtWaybillOrderNode> processNodes(List<KwtWaybillOrderNode> nodes) {
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(nodes)) {
            return nodes.stream()
                    .filter(x -> Objects.nonNull(x) && Objects.nonNull(x.getWeighbridgeId()) &&
                                Objects.nonNull(x.getRemark()) && x.getRemark().contains("称重"))
                    .sorted(Comparator.comparing(KwtWaybillOrderNode::getCreateTime))
                    .collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    /**
     * 处理关联运单
     */
    private List<KwtWaybillOrder> processBillOrders(List<KwtWaybillOrderSubtask> waybillOrderSubtasks) {
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(waybillOrderSubtasks)) {
            Set<Long> billOrderIds = waybillOrderSubtasks.stream()
                    .filter(Objects::nonNull)
                    .map(KwtWaybillOrderSubtask::getWOrderId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(billOrderIds)) {
                return kwtWaybillOrderRepository.queryByBillOrderIds(billOrderIds);
            }
        }
        return Lists.newArrayList();
    }

    /**
     * 处理装卸货信息
     */
    private Map<String, KwtWaybillOrderTicket> processTickets(List<KwtWaybillOrderTicket> orderTicketList) {
        return orderTicketList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(
                        ticket -> ticket.getWOrderId() + "-" + ticket.getType(),
                        Function.identity(),
                        (x, y) -> x));
    }


    @NotNull

    /**
     * 构建运单详情响应对象
     *
     * @param subtask 运单子任务信息
     * @param billOrder 运单主信息
     * @param logOrder 物流订单信息
     * @param truck 车辆信息
     * @param fleet 车队信息
     * @param goods 商品信息
     * @param keyAndAddressMap 地址映射关系
     * @param kwpGoods 商品详细信息
     * @param logisticsOrderUnitMap 物流订单单位映射
     * @param nodeList 节点轨迹列表
     * @param userCacheResDto 用户缓存信息
     * @param billOrders 运单列表
     * @param ticketMap 票据映射
     * @param dictValueAndDictResDtoMap 字典值映射
     * @param tradeContractUnitDtos 贸易合同单位列表
     * @return 运单详情响应对象
     */
    private WaybillOrderDetailResp getWaybillOrderDetailResp(KwtWaybillOrderSubtask subtask,
                                                                    KwtWaybillOrder billOrder,
                                                                    KwtLogisticsOrder logOrder,
                                                                    RTruckVo truck, RFleetVo fleet,
                                                                    KwtLogisticsOrderGoods goods,
                                                                    Map<String, KwtLogisticsOrderAddress> keyAndAddressMap,
                                                                    KwpGoods kwpGoods,
                                                                    Map<String, KwtLogisticsOrderUnit> logisticsOrderUnitMap,
                                                                    List<KwtWaybillOrderNode> nodeList,
                                                                    UserCacheResDto userCacheResDto,
                                                                    List<KwtWaybillOrder> billOrders,
                                                                    Map<String, KwtWaybillOrderTicket> ticketMap,
                                                                    Map<String, Map<String, String>> dictValueAndDictResDtoMap,
                                                                    List<TradeContractUnitDto> tradeContractUnitDtos,
                                                                    TradeContractGoodsDto contractGoodsDto) {
        WaybillOrderDetailResp resp = new WaybillOrderDetailResp();

        // 基本信息设置
        resp.setWaybillOrderId(String.valueOf(billOrder.getId()));
        resp.setWaybillOrderNo(billOrder.getWOrderNo());
        resp.setLogisticOrderId(String.valueOf(logOrder.getId()));
        resp.setLogisticOrderNo(logOrder.getLOrderNo());
        resp.setPriceType(String.valueOf(logOrder.getBillingMode()));
        resp.setPriceTypeDesc(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), logOrder.getBillingMode()));
        resp.setRemark(billOrder.getRemark());
        resp.setLabel(billOrder.getLabel());
        resp.setPassReason(billOrder.getPassReason());
        resp.setPassUrl(billOrder.getPassUrl());
        // 票据信息
        String shipmentTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode();
        KwtWaybillOrderTicket tareAmountTicket = ticketMap.getOrDefault(shipmentTicketKey, new KwtWaybillOrderTicket());
        resp.setTareAmount(tareAmountTicket.getTareAmount());
        resp.setGrossAmount(tareAmountTicket.getGrossAmount());

        // 卸货票据信息
        String unloadShipmentTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.TAKE.getCode();
        KwtWaybillOrderTicket unloadTareAmountTicket = ticketMap.getOrDefault(unloadShipmentTicketKey, new KwtWaybillOrderTicket());
        resp.setUnloadingTareAmount(unloadTareAmountTicket.getTareAmount());
        resp.setUnloadingGrossAmount(unloadTareAmountTicket.getGrossAmount());
        resp.setOrderType(logOrder.getOrderType());

//        if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_1.getValue())){
//            BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(subtask.getLoadAmount()) ?
//                    logOrder.getPrice().multiply(subtask.getLoadAmount()) : BigDecimal.ZERO;
//            BigDecimal actualGoodsPrice = Objects.nonNull(contractGoodsDto.getPrice()) && Objects.nonNull(subtask.getLoadAmount()) ?
//                    contractGoodsDto.getPrice().multiply(subtask.getLoadAmount()) : BigDecimal.ZERO;
//            resp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString() +"元");
//            resp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
//        }else if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_2.getValue())){
//            BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(subtask.getUnloadAmount()) ?
//                    logOrder.getPrice().multiply(subtask.getUnloadAmount()) : BigDecimal.ZERO;
//            BigDecimal actualGoodsPrice = Objects.nonNull(contractGoodsDto.getPrice()) && Objects.nonNull(subtask.getUnloadAmount()) ?
//                    contractGoodsDto.getPrice().multiply(subtask.getUnloadAmount()) : BigDecimal.ZERO;
//            resp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
//            resp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
//
//        }


        resp.setTruckNo(billOrder.getTruckNo());
        resp.setCarAxis(truck != null ? truck.getCarAxis() : "");
        resp.setFleetName(fleet != null ? fleet.getName() : "");
        resp.setDriverName(billOrder.getDriverName());
        resp.setDriverPhone(billOrder.getDriverPhone());
        resp.setDriverIdCard(billOrder.getDriverIdcard());

        // 商品信息
        if (kwpGoods != null) {
            Map<String, String> goodsTypeMap = dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), Collections.emptyMap());
            Map<String, String> goodsSpecMap = dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.GOODS_SPEC.getType(), Collections.emptyMap());
            String goodsType = goodsTypeMap.getOrDefault(kwpGoods.getGoodsType(), "");
            String goodsSpec = goodsSpecMap.getOrDefault(kwpGoods.getSpec(), "");
            resp.setGoodsName(kwpGoods.getName() + "/" + goodsType + "/" + goodsSpec);
        }

        // 地址信息
        String loadAddressKey = logOrder.getId() + "-" + AddressTypeEnum.SHIPMENT.getCode();
        String unloadAddressKey = logOrder.getId() + "-" + AddressTypeEnum.TAKE.getCode();
        KwtLogisticsOrderAddress loadAdd = keyAndAddressMap.getOrDefault(loadAddressKey, new KwtLogisticsOrderAddress());
        KwtLogisticsOrderAddress unLoadAdd = keyAndAddressMap.getOrDefault(unloadAddressKey, new KwtLogisticsOrderAddress());

        resp.setLoadAddress(loadAdd.getCityName() + loadAdd.getDetailAddress());
        resp.setUnloadAddress(unLoadAdd.getCityName() + unLoadAdd.getDetailAddress());
        resp.setDistanceKm(logOrder.getDistance());
        resp.setLoadLatitude(loadAdd.getLat());
        resp.setLoadLongitude(loadAdd.getLng());
        resp.setUnloadLatitude(unLoadAdd.getLat());
        resp.setUnloadLongitude(unLoadAdd.getLng());
        //装货净重
        resp.setLoadingNetWeight(subtask.getLoadAmount());
        resp.setTaskNum(subtask.getEntrustAmount());
        // 数量信息
        String unit = subtask.getUnit();
        resp.setTaskVolume(formatAmount(subtask.getEntrustAmount()) + unit);
        resp.setLoadAmount(formatAmount(subtask.getLoadAmount()) + unit);
        resp.setUnloadAmount(formatAmount(subtask.getUnloadAmount()) + unit);

        // 企业信息
        String transEntKey = logOrder.getId() + "-" + UnitTypeEnum.CONSIGN.getCode();
        String carrierEntKey = logOrder.getId() + "-" + UnitTypeEnum.CARRIAGE.getCode();
        KwtLogisticsOrderUnit transEnt = logisticsOrderUnitMap.getOrDefault(transEntKey, new KwtLogisticsOrderUnit());
        KwtLogisticsOrderUnit carrierEnt = logisticsOrderUnitMap.getOrDefault(carrierEntKey, new KwtLogisticsOrderUnit());
        resp.setTransEntName(transEnt.getFirmName());
        resp.setCarrierEntName(carrierEnt.getFirmName());


        //1.正常流程
        if (!Objects.equals(1, logOrder.getOrderType())) {
            // 供应商信息
            if (!CollectionUtils.isEmpty(tradeContractUnitDtos)) {
                tradeContractUnitDtos.stream()
                        .filter(x -> org.apache.commons.lang3.StringUtils.equals(x.getUnitType(), String.valueOf(CooperateTypeEnum.SUPPLIER.getCode())))
                        .findFirst()
                        .ifPresent(x -> resp.setSupplyEntName(x.getFirmName()));
            }
        } else {
            //2.原矿运输
            resp.setSupplyEntName(transEnt.getFirmName());
        }

        // 状态信息
        resp.setStatus(subtask.getStatus());
        resp.setStatusDesc(Objects.equals(subtask.getStatus(), CarWaybillV1Enum.COMPLETED.getCode())
                && Objects.equals(subtask.getRemark(), "空载离场") ? "空载完成" : CarWaybillV1Enum.geDesc(subtask.getStatus()));
        resp.setLegalLoad(Objects.isNull( truck)  ? null:truck.getLegalLoad());

        // 计算装货完成率
        BigDecimal loadAmount = subtask.getLoadAmount();
        BigDecimal entrustAmount = subtask.getEntrustAmount();
        BigDecimal unloadAmount = subtask.getUnloadAmount();

        resp.setLoadCompleteRate(calculatePercentage(loadAmount, entrustAmount));
        String lossRate = calculateLossRate(loadAmount, unloadAmount);
        resp.setLossRate(lossRate);

        // 轨迹记录
        if (!CollectionUtils.isEmpty(nodeList)) {
            List<WaybillOrderDetailResp.WeighingRecord> records = nodeList.stream()
                    .map(KwtWaybillOrderV1Service::convertToWeighingRecord)
                    .collect(Collectors.toList());
            resp.setWeighingRecords(records);
        }

        // 单据信息
        WaybillOrderDetailResp.BillInfo billInfo = new WaybillOrderDetailResp.BillInfo();
        billInfo.setUploadByLabel(userCacheResDto != null ? userCacheResDto.getName() : "");
        billInfo.setUploadTime(DateUtils.format(subtask.getUnloadUploadTime(), DateUtils.DATE_TIME_PATTERN));
        billInfo.setBillUrl(subtask.getUnloadUrl());
        resp.setBillInfo(billInfo);

        // 运单列表
        if (!CollectionUtils.isEmpty(billOrders)) {
            List<Long> billOrderIdList = billOrders.stream()
                    .filter(b -> Objects.equals(b.getStatus(), CarWaybillV1Enum.COMPLETION_LOADING.getCode())
                            && !Objects.equals(b.getId(), billOrder.getId()))
                    .map(KwtWaybillOrder::getId)
                    .collect(Collectors.toList());
            resp.setBillOrderIdList(billOrderIdList);
        }

        return resp;
    }

    /**
     * 格式化金额
     */
    private static String formatAmount(BigDecimal amount) {
        return amount != null ? amount.setScale(2, RoundingMode.HALF_UP).toPlainString() : "0.00";
    }

    /**
     * 计算百分比
     */
    private static String calculatePercentage(BigDecimal numerator, BigDecimal denominator) {
        if (numerator != null && denominator != null && denominator.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal rate = numerator.divide(denominator, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(2, RoundingMode.HALF_UP);
            return rate.toPlainString() + "%";
        }
        return "0.00%";
    }

    /**
     * 计算货损率
     */
    private static String calculateLossRate(BigDecimal loadAmount, BigDecimal unloadAmount) {
        if (loadAmount != null && unloadAmount != null && loadAmount.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal rate = loadAmount.subtract(unloadAmount)
                    .divide(loadAmount, 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))
                    .setScale(2, RoundingMode.HALF_UP);
            return rate.toPlainString() + "%";
        }
        return "0.00%";
    }

    /**
     * 转换为称重记录
     */
    private static WaybillOrderDetailResp.WeighingRecord convertToWeighingRecord(KwtWaybillOrderNode node) {
        WaybillOrderDetailResp.WeighingRecord record = new WaybillOrderDetailResp.WeighingRecord();
        record.setWeighingTime(DateUtils.format(node.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
        record.setWeighingDesc(node.getRemark());
        record.setWeighingName(node.getWeighbridgeName());
        record.setWeighingImgUrl(node.getWeighUrl());
        return record;
    }


//    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(name = "default_tx_group")
    public Boolean reviewWaybillOrder(@Valid ReviewWaybillOrderReq req) {
        log.info("审核运单请求参数：{}", JSON.toJSONString(req));
        Long waybillId = Long.parseLong(req.getWaybillId());
        Integer status = Integer.parseInt(req.getStatus());
        //查询运单信息
        KwtWaybillOrder billOrder = kwtWaybillOrderRepository.queryByBillOrderId(waybillId);
        if (Objects.isNull(billOrder)){
            throw new BusinessException("运单信息不存在");
        }
        KwtWaybillOrderSubtask subtask = kwtWaybillOrderSubtaskRepository.queryByBillOrderId(waybillId);
        if (Objects.isNull(subtask)){
            throw new BusinessException("子运单信息不存在");
        }
        KwtLogisticsOrder kwtLogistics= kwtLogisticsOrderRepository.queryByLogisticsOrderId(subtask.getLOrderId());
        KwtWaybillOrder updateOrder = new KwtWaybillOrder();
        updateOrder.setId(billOrder.getId());
        KwtWaybillOrderSubtask updateSubtask = new KwtWaybillOrderSubtask();
        updateSubtask.setId(subtask.getId());
        //KwtWaybillOrderTicket kwtWaybillOrderTicket = new KwtWaybillOrderTicket();
        //单证审核 运单当前状态是已卸货，传入的订单是已完成
        List<Integer> statusList = Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.REVIEW_REJECTION.getCode());
        if (statusList.contains( status) && Objects.equals(billOrder.getStatus(), CarWaybillV1Enum.COMPLETION_LOADING.getCode())){
            updateOrder.setStatus( status);
            updateOrder.setRemark(req.getRemark());
            updateSubtask.setStatus(status);
            updateSubtask.setRemark(req.getRemark());
            updateSubtask.setUnloadAmount(org.apache.commons.lang3.StringUtils.isBlank(req.getUnloadAmount()) ? null  :  new BigDecimal(req.getUnloadAmount()));
//            if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getAddressUrl())){
//                updateSubtask.setUnloadUrl(req.getAddressUrl());
//            }
            if(org.apache.commons.lang3.StringUtils.isNotBlank(req.getUploadUser())){
                updateSubtask.setUnloadOperator(Long.valueOf(req.getUploadUser()));
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getUploadTime())){
                updateSubtask.setUnloadUploadTime(DateUtils.parse(req.getUploadTime(), DateUtils.DATE_TIME_PATTERN));
            }
            boolean b = kwtWaybillOrderRepository.updateById(updateOrder) && kwtWaybillOrderSubtaskRepository.updateById(updateSubtask);
            //获取更新 订单状态
            if (Objects.equals(status, CarWaybillV1Enum.COMPLETED.getCode())){
                KwtLogisticsOrder kwtLogisticsOrder = getKwtLogisticsOrder(kwtLogistics, subtask,status);
                kwtLogisticsOrderRepository.updateById(kwtLogisticsOrder);
            }

            //如果物流订单状态是已完成需要通知贸易订单完成

            // 存储记录
            String remark = null;
            if (Objects.equals(status, CarWaybillV1Enum.REVIEW_REJECTION.getCode())){
                 //remark = "审核驳回，运单【"+ billOrder.getWOrderNo() + "】已驳回";
                remark = "因【"+ req.getRemark() + "】审核未通过";
            }else {
                 remark = "审核通过，卸货量【"+ req.getUnloadAmount() + "】，运单【"+ billOrder.getWOrderNo() + "】已完成";
            }

            saveNode(billOrder, subtask, status,remark,req.getAddressUrl());
            if (!b ){
                throw new BusinessException("审核运单失败");
            }
            //查询司机是否存在已绑定的车辆
            if (Objects.equals(status, CarWaybillV1Enum.COMPLETED.getCode())){
                log.info("运单审核完成，解绑司机与车辆关系，运单id：{},企业id:{},司机id：{}", billOrder.getId(), billOrder.getEntId(), billOrder.getDriverId());
                try {
                    remoteFleetService.unbindTruck(billOrder.getEntId(), billOrder.getDriverId());
                } catch (Exception e) {
                    log.error("解绑司机与车辆关系失败，运单id：{},企业id:{},司机id：{},异常信息：{}", billOrder.getId(), billOrder.getEntId(), billOrder.getDriverId(), e.getMessage());
                }
            }

            //计算司机分值
            calculateAutoDispatchScore(billOrder, status);

            return Boolean.TRUE;
        }
        // 驳回的订单可以通过完善单证变成已完成
        if (Objects.equals(billOrder.getStatus(), CarWaybillV1Enum.REVIEW_REJECTION.getCode()) && Objects.equals(status,
                CarWaybillV1Enum.COMPLETED.getCode())){
            updateOrder.setStatus(status);
            updateOrder.setRemark(req.getRemark());
            updateSubtask.setStatus(status);
            updateSubtask.setRemark(req.getRemark());
            updateSubtask.setUnloadAmount(org.apache.commons.lang3.StringUtils.isNotBlank(req.getUnloadAmount()) ? new BigDecimal(req.getUnloadAmount()) : null);
            if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getAddressUrl())){
                updateSubtask.setUnloadUrl(req.getAddressUrl());
            }
            if(org.apache.commons.lang3.StringUtils.isNotBlank(req.getUploadUser())){
                updateSubtask.setUnloadOperator(Long.valueOf(req.getUploadUser()));
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(req.getUploadTime())){
                updateSubtask.setUnloadUploadTime(DateUtils.parse(req.getUploadTime(), DateUtils.DATE_TIME_PATTERN));
            }
            boolean b = kwtWaybillOrderRepository.updateById(updateOrder) && kwtWaybillOrderSubtaskRepository.updateById(updateSubtask);
            // 存储记录
            Long currentRoleId = LoginUserHolder.getCurrentRoleId();
            KwsRoleDto kwsRoleDto = remoteSystemService.queryByRoleIdAndEntId(currentRoleId);
            String roleName =  Objects.nonNull(kwsRoleDto) ? kwsRoleDto.getName() : "";
            String remark = "【"+roleName+"】【"+LoginUserHolder.getUserName()+"】已完善单证，卸货量【"+ req.getUnloadAmount() + "吨】，运单【"+ billOrder.getWOrderNo() + "】已完成";
            saveNode(billOrder, subtask, status,remark,req.getAddressUrl());
            if (!b ){
               throw new BusinessException("完善单证失败");
            }
            //如果审核的状态是 完成，那么就要去查询物流订单状态是完结中，并且所有物流订单下的运单全部是完成或者取消如果是则更新状态为已完成
            //修改物流订单数据
            KwtLogisticsOrder kwtLogisticsOrder = getKwtLogisticsOrder(kwtLogistics, subtask,status);
            kwtLogisticsOrderRepository.updateById(kwtLogisticsOrder);
           // updateLogisticOrder(subtask,kwtLogistics);
            //查询司机是否存在已绑定的车辆
            log.info("运单由审核驳回审核完成，解绑司机与车辆关系，运单id：{},企业id:{},司机id：{}", billOrder.getId(), billOrder.getEntId(), billOrder.getDriverId());
            remoteFleetService.unbindTruck(billOrder.getEntId(), billOrder.getDriverId());
            return Boolean.TRUE;
        }
        calculateFreight(kwtLogistics);
        noticeTraderOrder(status, subtask,kwtLogistics);

        return Boolean.FALSE;
    }

    //计算运费
    private void calculateFreight(KwtLogisticsOrder kwtLogistics){
        if(LogisticsOrderV1Enum.COMPLETED.getCode().equals(kwtLogistics.getStatus())){
            //物流订单已完结，计算待付运费
            if(Objects.equals(kwtLogistics.getSettlement(),1)){
                //todo 普通结算

            }else if(Objects.equals(kwtLogistics.getSettlement(),2)) {
                //记账模式
                //1解冻运费
                List<KwtLogisticsOrderUnit> orderUnits = kwtLogisticsOrderUnitRepository.queryByLOrderId(kwtLogistics.getId());
                Map<Integer, Long> map = orderUnits.stream().collect(Collectors.toMap(KwtLogisticsOrderUnit::getUnitType, KwtLogisticsOrderUnit::getEntId, (v1, v2) -> v1));
                WalletPayableDto unFreezePayableDto = new WalletPayableDto();
                unFreezePayableDto.setConsignEntId(map.get(1));
                unFreezePayableDto.setCarriageEntId(map.get(2));
                unFreezePayableDto.setOrderNo(kwtLogistics.getLOrderNo());
                unFreezePayableDto.setOrderType(5);
                unFreezePayableDto.setTradeType(5);
                unFreezePayableDto.setRemark("物流订单号：" + unFreezePayableDto.getOrderNo() + "，订单完结解冻");
                log.info("物流订单号：{}，订单完结解冻进行中运费，参数：{}", unFreezePayableDto.getOrderNo(),JSON.toJSONString(unFreezePayableDto));
                BaseResult<Object> unFreezeResult = paymentFeignService.updatePayable(unFreezePayableDto);
                if(unFreezeResult.getCode()!= HttpStatus.SUCCESS_CODE){
                    log.error("物流订单号：{}，订单完结解冻失败,异常信息为：{}",unFreezePayableDto.getOrderNo(),unFreezeResult.getMessage());
                    throw new BusinessException("物流订单号："+unFreezePayableDto.getOrderNo()+"，订单完结解冻失败");
                }
                //2计算待付运费
                WalletPayableDto consumePayableDto = new WalletPayableDto();
                consumePayableDto.setConsignEntId(map.get(1));
                consumePayableDto.setCarriageEntId(map.get(2));
                consumePayableDto.setOrderNo(kwtLogistics.getLOrderNo());
                consumePayableDto.setOrderType(5);
                consumePayableDto.setTradeType(6);
                consumePayableDto.setTradeAmount(kwtLogistics.getTotalUnloadAmount().multiply(kwtLogistics.getPrice()));
                consumePayableDto.setRemark("物流订单号：" + consumePayableDto.getOrderNo() + "，订单完结消费");
                log.info("物流订单号：{}，订单完结消费，参数：{}", consumePayableDto.getOrderNo(),JSON.toJSONString(consumePayableDto));
                BaseResult<Object> consumeResult = paymentFeignService.updatePayable(consumePayableDto);
                if(consumeResult.getCode()!= HttpStatus.SUCCESS_CODE){
                    log.error("物流订单号：{}，订单完结消费失败,异常信息为：{}",consumePayableDto.getOrderNo(),consumeResult.getMessage());
                    throw new BusinessException("物流订单号："+consumePayableDto.getOrderNo()+"，订单完结消费失败");
                }
            }
        }
    }

    private void updateLogisticOrder(KwtWaybillOrderSubtask subtask,KwtLogisticsOrder kwtLogistics) {
        if (Objects.nonNull(kwtLogistics) && Objects.equals(kwtLogistics.getStatus(), LogisticsOrderV1Enum.NEARING_COMPLETION.getCode())){
            List<KwtWaybillOrderSubtask> waybillOrderSubtasks = kwtWaybillOrderSubtaskRepository.queryByLogId(subtask.getLOrderId());
            boolean b2 = waybillOrderSubtasks.stream()
                    .allMatch(x -> Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode()).contains(x.getStatus()));
            KwtLogisticsOrder logisticsOrder = new KwtLogisticsOrder();
            logisticsOrder.setId(kwtLogistics.getId());
            if (b2){
                logisticsOrder.setStatus(LogisticsOrderV1Enum.COMPLETED.getCode());
                log.info("运单状态由审核驳回变成审核完成，修改物流订单状态为已完成，物流订单id：{}", kwtLogistics.getId());

            }
            BigDecimal unloadAmount  = Objects.isNull(kwtLogistics.getUnloadAmount())  ? BigDecimal.ZERO: kwtLogistics.getUnloadAmount();
            BigDecimal subUnloadAmount = Objects.isNull(subtask.getUnloadAmount()) ? BigDecimal.ZERO: subtask.getUnloadAmount();
            BigDecimal entrustAmount  = Objects.isNull(kwtLogistics.getEntrustAmount())  ? BigDecimal.ZERO: kwtLogistics.getEntrustAmount();
            BigDecimal subEntrustAmount = Objects.isNull(subtask.getEntrustAmount()) ? BigDecimal.ZERO: subtask.getEntrustAmount();
            KwtLogisticsOrder kwtLogisticsOrder = new KwtLogisticsOrder();
            kwtLogisticsOrder.setId(kwtLogistics.getId());
            BigDecimal subtractAmount = entrustAmount.subtract(subEntrustAmount);
            BigDecimal entrust = subtractAmount.compareTo(BigDecimal.ZERO) >= 0
                    ? subtractAmount : new BigDecimal("0.00");
            kwtLogisticsOrder.setEntrustAmount(entrust);
            kwtLogisticsOrder.setTotalUnloadAmount(unloadAmount.add(subUnloadAmount));
            kwtLogisticsOrderRepository.updateById(logisticsOrder);
        }
    }

    /**
     * 自动派单计算司机分值
     * @param billOrder
     */
    protected void calculateAutoDispatchScore(KwtWaybillOrder billOrder, Integer status) {
        try {
            if (!DispatchWayEnums.AUTO_DISPATCH.getCode().equals(billOrder.getDispatchWay())) {
                return;
            }
            Long supEntId = getSupplierId(billOrder);
            //查询物流订单
            KwtLogisticsOrder logisticsOrder = kwtLogisticsOrderRepository.queryByLogisticsOrderId(billOrder.getLOrderId());
            // 获取司机行为规则配置（司机违规取消运单分钟数）
            DriverConductRulesVO driverRulesVO = remoteFleetService.findDriverConductRulesByEntId(supEntId);
            if (driverRulesVO == null) {
                throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "未找到司机行为规则数据！");
            }

            //1. 运单单据错误被驳回
            checkRefuseScore(billOrder, status, driverRulesVO);

            //运单没通过，不执行以下逻辑
            if (!Objects.equals(status, CarWaybillV1Enum.COMPLETED.getCode())) {
                return;
            }

            //2. 校验司机运单完成是否超时
            checkCompletionTimeout(billOrder, logisticsOrder, driverRulesVO);

            //3. 校验司机连续准时卸货（审核通过）
            checkContinuousUnload(billOrder, logisticsOrder, driverRulesVO);

            //4. 校验司机连续准确填写卸货信息（审核通过）
            checkContinuousPass(billOrder, driverRulesVO);
        } catch (Exception e) {
            log.info("司机分数计算失败！", e);
        }


    }

    /**
     * 运单被驳回，扣减司机分数
     * @param waybillOrder
     */
    private void checkRefuseScore(KwtWaybillOrder waybillOrder, Integer status, DriverConductRulesVO driverRulesVO) {
        //运单驳回
        if (!Objects.equals(status, CarWaybillV1Enum.REVIEW_REJECTION.getCode())) {
            return;
        }
        //单据错误驳回分数
        Integer documentErrorScore = driverRulesVO.getDocumentErrorMissingScore();
        if (documentErrorScore <= 0) {
            log.warn("【单据错误/缺失】司机扣分失败：企业{}的司机单据错误/缺失分数配置异常，运单ID：{}", waybillOrder.getEntId(), waybillOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "【单据错误/缺失】司机扣分失败，单据错误/缺失分数配置需大于0!");
        }

        //1、更新司机分数（减分）
        documentErrorScore = -Math.abs(documentErrorScore);
        updateDriverScore(driverRulesVO.getEntId(), waybillOrder.getEntId(), waybillOrder.getDriverId(), documentErrorScore, "单据错误/缺失");

        //2、更新企业分数（减分）
        updateLogEntScore(waybillOrder, driverRulesVO.getEntId(), documentErrorScore, "单据错误/缺失");

    }

    /**
     * 校验司机运单完成是否超时
     * @param waybillOrder
     */
    private void checkCompletionTimeout(KwtWaybillOrder waybillOrder, KwtLogisticsOrder logisticsOrder,
                                        DriverConductRulesVO driverRulesVO) {
        //单趟严重超时倍数
        BigDecimal timeoutMultiple = driverRulesVO.getUnloadSeriousTimeoutMultiple();
        //单趟严重超时分数
        Integer timeoutScore = driverRulesVO.getUnloadSeriousTimeoutScore();
        if (timeoutMultiple == null || timeoutMultiple.compareTo(BigDecimal.ZERO) <= 0 || timeoutScore <= 0) {
            log.warn("【卸货严重超时】司机扣分失败：企业{}的司机卸货严重超时倍数/分数配置异常，运单ID：{}", waybillOrder.getEntId(), waybillOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "【卸货严重超时】司机扣分失败，司机卸货严重超时配置倍数/分数需大于0!");
        }

        //校验司机运单完成是否超时
        Boolean isTimeOut = isTimeOut(waybillOrder, logisticsOrder, driverRulesVO.getEntId(), timeoutMultiple);
        if (isTimeOut) {
            //1、更新司机分数（减分）
            timeoutScore = -Math.abs(timeoutScore);
            updateDriverScore(driverRulesVO.getEntId(), waybillOrder.getEntId(), waybillOrder.getDriverId(), timeoutScore, "卸货严重超时");

            //2、更新企业分数（减分）
            updateLogEntScore(waybillOrder, driverRulesVO.getEntId(), timeoutScore, "卸货严重超时");
        }
    }

    /**
     * 校验司机运单完成是否超时
     * @param waybillOrder 运单
     * @param logisticsOrder  运单地址
     */
    protected Boolean isTimeOut(KwtWaybillOrder waybillOrder, KwtLogisticsOrder logisticsOrder, Long supeEntId, BigDecimal timeoutMultiple) {
        log.info("校验司机运单完成是否超时：运单ID：{}", waybillOrder.getId());
        //运单总耗时(秒)
        Long orderTotalTimes = calOrderTotalTimes(waybillOrder);
        //平台配置的单趟总耗时(秒)
        Long singleTripTotalTimes = calSingleTripTotalTimes(waybillOrder, logisticsOrder, supeEntId);
        //计算超时阈值
        BigDecimal threshold = timeoutMultiple.compareTo(BigDecimal.ZERO) == 0 ?
                new BigDecimal(singleTripTotalTimes) : timeoutMultiple.multiply(new BigDecimal(singleTripTotalTimes));
        BigDecimal actualTimes = new BigDecimal(orderTotalTimes);
        if (actualTimes.compareTo(threshold) > 0) {
            log.warn("【司机运单超时】运单ID：{}，实际总耗时：{}分钟，平台单趟耗时：{}分钟", waybillOrder.getId(), orderTotalTimes, singleTripTotalTimes);
            return true;
        }
        return false;
    }

    /**
     * 计算司机接单到结束的总耗时
     * @param waybillOrder
     * @return
     */
    private Long calOrderTotalTimes(KwtWaybillOrder waybillOrder) {
        //司机接单时间
        KwtWaybillOrderNode takingOrderNodes = kwtWaybillOrderNodeRepository.queryNodesByOrderId(waybillOrder.getId(), CarWaybillV1Enum.PENDING_VEHICLE.getCode());
        if (takingOrderNodes == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_NODE_NOT_EXIST, "未找到关联的运单节点数据！");
        }
        Date takingOrderTime = takingOrderNodes.getCreateTime() != null ? takingOrderNodes.getCreateTime() : null;
        //司机完成运单时间
        KwtWaybillOrderNode overOrderNodes = kwtWaybillOrderNodeRepository.queryNodesByOrderId(waybillOrder.getId(), CarWaybillV1Enum.COMPLETED.getCode());
        if (overOrderNodes == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_NODE_NOT_EXIST, "未找到关联的运单节点数据！");
        }
        Date overOrderTime = overOrderNodes.getCreateTime() != null ? overOrderNodes.getCreateTime() : null;
        //运单总耗时（秒）
        Long orderTotalTimes = DateUtils.calculateTimeDiffMinutes(takingOrderTime, overOrderTime);
        log.info("司机完成运单总耗时：{}", orderTotalTimes);
        return orderTotalTimes;
    }

    /**
     * 计算平台配置的运单单趟总耗时
     * @param waybillOrder
     * @param logisticsOrder
     * @return
     */
    private Long calSingleTripTotalTimes(KwtWaybillOrder waybillOrder, KwtLogisticsOrder logisticsOrder, Long supeEntId) {
        // 获取自动派单系数配置（单趟耗时 = 装货时间 + 卸货时间 + 运输时间 + 返回时间）
        TruckDispatchCoefficientVO truckDispatchVO = remoteFleetService.findAutoTruckDispatchByEntId(supeEntId);
        if (truckDispatchVO == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "未找到自动派车系数！");
        }
        //装货时长
        Integer vehicleLoadingHours = truckDispatchVO.getVehicleLoadingHours();
        //卸货货时长
        Integer vehicleUnloadingHours = truckDispatchVO.getVehicleUnloadingHours();
        //平均行驶速度
        Integer vehicleAvgSpeed = truckDispatchVO.getVehicleAvgSpeed();
        if (vehicleLoadingHours <= 0 || vehicleUnloadingHours <= 0 || vehicleAvgSpeed <= 0) {
            log.warn("企业{}的司机装货时长/卸货时长/平均行驶速度配置数据异常（装货：{}，卸货：{}，速度：{}），运单ID：{}",
                    waybillOrder.getEntId(), vehicleLoadingHours, vehicleUnloadingHours, vehicleAvgSpeed, waybillOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "司机配置的装货时长/卸货时长/平均行驶速度需要≥0!");
        }
        //应卸货地与实际卸货地之间距离
        String distance = logisticsOrder.getDistance();
        if (StringUtils.isBlank(distance)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "物流运单装货地址有误!");
        }
        //运输时间/返回时间(小时) = 两地距离除以平均行驶速度
        BigDecimal bdDividend = new BigDecimal(distance);
        BigDecimal bdDivisor = BigDecimal.valueOf(vehicleAvgSpeed);
        //运输时间小时
        BigDecimal transportTimeHours = bdDividend.divide(bdDivisor, 4, RoundingMode.HALF_UP);
        //运输时间（秒）
        long transportTimeMillis = transportTimeHours.multiply(BigDecimal.valueOf(3600))
                .setScale(0, RoundingMode.HALF_UP).longValue();
        //往返时间=运输时间
        long returnTimeMillis = transportTimeMillis;
        //单趟总耗时
        Long singleTripTotalTimes = TimeUnit.MINUTES.toSeconds(vehicleLoadingHours) + TimeUnit.MINUTES.toSeconds(vehicleUnloadingHours) + transportTimeMillis + returnTimeMillis;
        log.info("平台配置的运单单趟总耗时：{}", singleTripTotalTimes);
        return singleTripTotalTimes;

    }

    /**
     * 校验司机连续准时卸货
     * @param waybillOrder
     */
    private void checkContinuousUnload(KwtWaybillOrder waybillOrder, KwtLogisticsOrder logisticsOrder, DriverConductRulesVO driverRulesVO) {
        //连续卸货次数
        Integer continuousOnTimes = driverRulesVO.getContinuousOnTimeUnloadTimes();
        //连续卸货加分分数
        Integer continuousScore = driverRulesVO.getContinuousOnTimeUnloadScore();
        if (continuousOnTimes <= 0 || continuousScore <= 0) {
            log.warn("【连续准时卸货】获取连续准时卸货数据失败：企业{}的连续按时到场次数/分数配置异常，运单ID：{}", driverRulesVO.getEntId(), waybillOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "【连续准时卸货】配置的次数/分数需大于0!");
        }

        //查询该司机连续审核通过节点数据
        List<KwtWaybillOrderNode> waybillOrderNodeList = getWaybillOrderNodesByStatus(waybillOrder, continuousOnTimes);
        if (waybillOrderNodeList.size() != continuousOnTimes) {
            log.info("司机{}最近连续准时卸货记录不足{}条，当前：{}", waybillOrder.getDriverId(), continuousOnTimes, waybillOrderNodeList.size());
            return;
        }
        //记录连续审核通过次数
        List<Long> nodeIds = new ArrayList<>();
        boolean allOnTime = true;
        for (KwtWaybillOrderNode orderNode : waybillOrderNodeList) {
            if (orderNode.getContinuous() == 1) {
                break;
            }
            //计算每次运单是否准时卸货
            KwtWaybillOrder wOrder = kwtWaybillOrderRepository.queryByBillOrderId(orderNode.getWOrderId());
            if (isTimeOut(wOrder, logisticsOrder, driverRulesVO.getEntId(), BigDecimal.ZERO)) {
                log.info("司机{}存在超时情况，运单id：{}", orderNode.getDriverId(), orderNode.getWOrderId());
                allOnTime = false;
                break;
            }
            nodeIds.add(orderNode.getId());
        }
        if (allOnTime && nodeIds.size() == continuousOnTimes) {
            //1. 给连续的10次节点数据打标
            updateNode(waybillOrder, nodeIds, continuousScore);

            //2 .更新司机分数（加分）
            updateDriverScore(driverRulesVO.getEntId(), waybillOrder.getEntId(), waybillOrder.getDriverId(), continuousScore, "连续准时卸货");

            //3. 更新企业分数（加分）
            updateLogEntScore(waybillOrder, driverRulesVO.getEntId(), continuousScore, "连续准时卸货");
        }
    }

    /**
     * 校验司机连续准确填写卸货信息
     * @param waybillOrder
     */
    private void checkContinuousPass(KwtWaybillOrder waybillOrder, DriverConductRulesVO driverRulesVO) {
        //连续卸货次数
        Integer continuousUnloadTimes = driverRulesVO.getContinuousAccurateUnloadTimes();
        //连续卸货加分分数
        Integer continuousScore = driverRulesVO.getContinuousAccurateUnloadScore();
        if (continuousUnloadTimes <= 0 || continuousScore <= 0) {
            log.warn("【连续准确填写卸货信息】企业{}的连续准确填写卸货信息配置的次数/分数异常，运单ID：{}", driverRulesVO.getEntId(), waybillOrder.getId());
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "【连续准确填写卸货信息】配置的次数/分数需大于0!");
        }

        //查询该司机连续审核通过节点数据
        List<KwtWaybillOrderNode> waybillOrderNodeList = getWaybillOrderNodesByStatus(waybillOrder, continuousUnloadTimes);
        if (waybillOrderNodeList == null)  {
            return;
        }
        //记录连续审核通过次数
        List<Long> nodeIds = new ArrayList<>();
        boolean allOnTime = true;
        for (KwtWaybillOrderNode orderNode : waybillOrderNodeList) {
            if (orderNode.getIsBonus() == 2) {
                break;
            }
            //计算每次运单是否连续审核通过
            KwtWaybillOrderNode wOrderNode = kwtWaybillOrderNodeRepository.queryNodesByOrderId(orderNode.getWOrderId(), CarWaybillV1Enum.REVIEW_REJECTION.getCode());
            if (wOrderNode != null) {
                log.info("司机{}存在审核驳回的情况，运单id：{}", orderNode.getDriverId(), orderNode.getWOrderId());
                allOnTime = false;
                break;
            }
            nodeIds.add(orderNode.getId());
        }
        if (allOnTime && nodeIds.size() == continuousUnloadTimes) {
            //1. 给连续的10次节点数据打标
            updateReviewNode(waybillOrder, nodeIds, continuousScore);

            //2 .更新司机分数（加分）
            updateDriverScore(driverRulesVO.getEntId(), waybillOrder.getEntId(), waybillOrder.getDriverId(), continuousScore, "连续准确填写卸货信息");

            //3. 更新企业分数（加分）
            updateLogEntScore(waybillOrder, driverRulesVO.getEntId(), continuousScore, "连续准确填写卸货信息");
        }
    }

    /**
     * 查询该司机连续卸货节点数据
     * @param waybillOrder
     * @param continuousOnTimes
     * @return
     */
    protected List<KwtWaybillOrderNode> getWaybillOrderNodesByStatus(KwtWaybillOrder waybillOrder, Integer continuousOnTimes) {
        //司机运单数据
        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryByEntId(waybillOrder.getEntId(), waybillOrder.getDriverId());
        if (CollectionUtils.isEmpty(waybillOrders)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_FOUND, "物流运单不存在！");
        }
        List<Long> wOrderIds = waybillOrders.stream().map(KwtWaybillOrder::getId).collect(Collectors.toList());
        //查询司机的节点数据
        List<KwtWaybillOrderNode> waybillOrderNodeList = kwtWaybillOrderNodeRepository
                .queryContinuousNodesByDriverId(wOrderIds, waybillOrder.getDriverId(),  CarWaybillV1Enum.COMPLETED.getCode());
        if (CollectionUtils.isEmpty(waybillOrderNodeList) || waybillOrderNodeList.size() < continuousOnTimes) {
            log.info("司机{}按时接节点不足{}次，当前记录数：{}", waybillOrder.getDriverId(), continuousOnTimes, waybillOrderNodeList.size());
            return null;
        }

        //取continuousOnTimes条节点数据
        return waybillOrderNodeList.stream().sorted(Comparator.comparing(KwtWaybillOrderNode::getCreateTime).reversed())
                .limit(continuousOnTimes)
                .collect(Collectors.toList());
    }

    /**
     * 给连续的10次的节点数据打标
     */
    protected void updateNode(KwtWaybillOrder waybillOrder, List<Long> nodeIds, Integer continuousOnTimeScore) {
        KwtWaybillOrderNode updateEntity = new KwtWaybillOrderNode();
        updateEntity.setContinuous(1);
        LambdaQueryWrapper<KwtWaybillOrderNode> updateWrapper = new LambdaQueryWrapper<KwtWaybillOrderNode>()
                .in(KwtWaybillOrderNode::getId, nodeIds);
        kwtWaybillOrderNodeRepository.update(updateEntity, updateWrapper);
        log.info("司机{}连续准时卸货,加分：{}，节点ID：{}", waybillOrder.getDriverId(), continuousOnTimeScore, JSON.toJSONString(nodeIds));
    }

    /**
     * 给连续的10次的节点数据打标
     */
    protected void updateReviewNode(KwtWaybillOrder waybillOrder, List<Long> nodeIds, Integer continuousOnTimeScore) {
        KwtWaybillOrderNode updateEntity = new KwtWaybillOrderNode();
        updateEntity.setIsBonus(2);
        LambdaQueryWrapper<KwtWaybillOrderNode> updateWrapper = new LambdaQueryWrapper<KwtWaybillOrderNode>()
                .in(KwtWaybillOrderNode::getId, nodeIds);
        kwtWaybillOrderNodeRepository.update(updateEntity, updateWrapper);
        log.info("司机{}连续准确填写卸货信息,加分：{}，节点ID：{}", waybillOrder.getDriverId(), continuousOnTimeScore, JSON.toJSONString(nodeIds));
    }

    // 查询供应商id
    protected Long getSupplierId(KwtWaybillOrder waybillOrder) {
        if (waybillOrder == null) {
            return 0L;
        }
        //查询订单托运单位（自动派单订单承运单位只为供应商）
        KwtLogisticsOrderUnit logisticsOrderUnit = kwtLogisticsOrderUnitRepository.queryByLOrderIdAndUnitType(waybillOrder.getLOrderId(), 1);
        if (logisticsOrderUnit == null || logisticsOrderUnit.getEntId() == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ENT, "未找到关联的物流订单托运企业（供应商）！");
        }
        return logisticsOrderUnit.getEntId();
    }

    /**
     * 修改司机评分
     * @param supeEntId
     * @param entId
     * @param driverId
     * @param score
     */
    public void updateDriverScore(Long supeEntId, Long entId, Long driverId, Integer score, String action) {
        RUpdateDriverScoreDto dto = new RUpdateDriverScoreDto();
        dto.setSupEntId(supeEntId);
        dto.setLogEntId(entId);
        dto.setDriverId(driverId);
        dto.setScore(BigDecimal.valueOf(score));
        dto.setAction(action);
        remoteFleetService.updateDriverScoreByEntId(dto);
    }

    /**
     * 更新企业评分
     * @param waybillOrder
     * @param supplierId
     * @param score
     */
    public void updateLogEntScore(KwtWaybillOrder waybillOrder, Long supplierId, Integer score, String remark) {
        LogisticsScoreDetailFeignDto detailDto = new LogisticsScoreDetailFeignDto();
        detailDto.setProviderEntId(supplierId);
        detailDto.setLogisticsEntId(waybillOrder.getEntId());
        detailDto.setPhone(waybillOrder.getDriverPhone());
        detailDto.setAction(remark);
        detailDto.setScoreChange(BigDecimal.valueOf(score));
        logisticsScoreFeignService.updateLogisticsScore(detailDto);
    }


    private void noticeTraderOrder(Integer status, KwtWaybillOrderSubtask subtask,KwtLogisticsOrder kwtLogistics) {
        if (!Objects.equals(status,CarWaybillV1Enum.COMPLETED.getCode())){
            log.info("物流订单状态不是已完成，不通知贸易订单完结");
           return;
        }
        TradeOrderSettlePara tradeOrderSettlePara = new TradeOrderSettlePara();
        tradeOrderSettlePara.setTOrderId(kwtLogistics.getTOrderId());
        tradeOrderSettlePara.setUnloadAmount(subtask.getUnloadAmount());
        log.info("运单审核通过修改贸易订单状态请求参数：{}",JSON.toJSONString(tradeOrderSettlePara));
        tradeOrderInfoService.orderSettle(tradeOrderSettlePara);
    }

    private void saveNode(KwtWaybillOrder billOrder, KwtWaybillOrderSubtask subtask, Integer status,String remark,String imageUrl) {
        KwtWaybillOrderNode kwtWaybillOrderNode = new KwtWaybillOrderNode();
        kwtWaybillOrderNode.setTruckId(billOrder.getTruckId());
        kwtWaybillOrderNode.setTruckNo(billOrder.getTruckNo());
        kwtWaybillOrderNode.setDriverId(billOrder.getDriverId());
        kwtWaybillOrderNode.setDriverName(billOrder.getDriverName());

        kwtWaybillOrderNode.setWOrderId(billOrder.getId());
        kwtWaybillOrderNode.setWSubtaskId(subtask.getId());
        kwtWaybillOrderNode.setOrderStatus(status);
        kwtWaybillOrderNode.setRemark(remark);
        kwtWaybillOrderNode.setCreateBy(LoginUserHolder.getUserId());
        kwtWaybillOrderNode.setTruckId(billOrder.getTruckId());
        kwtWaybillOrderNode.setWeighUrl(imageUrl);
        kwtWaybillOrderNodeRepository.save(kwtWaybillOrderNode);
    }

    @NotNull
    private  KwtLogisticsOrder getKwtLogisticsOrder(KwtLogisticsOrder kwtLogistics, KwtWaybillOrderSubtask subtask,Integer status) {
        if (Objects.isNull(kwtLogistics)){
            throw new BusinessException("物流订单信息不存在");
        }
        //查询贸易订单
        //调物流订单完结订单
       // BigDecimal loadAmount  = Objects.isNull(kwtLogistics.getLoadAmount())  ? BigDecimal.ZERO: kwtLogistics.getLoadAmount();
        //BigDecimal subLoadAmount = Objects.isNull(subtask.getLoadAmount()) ? BigDecimal.ZERO: subtask.getLoadAmount();
        BigDecimal unloadAmount  = Objects.isNull(kwtLogistics.getUnloadAmount())  ? BigDecimal.ZERO: kwtLogistics.getUnloadAmount();
        BigDecimal subUnloadAmount = Objects.isNull(subtask.getUnloadAmount()) ? BigDecimal.ZERO: subtask.getUnloadAmount();
        BigDecimal entrustAmount  = Objects.isNull(kwtLogistics.getEntrustAmount())  ? BigDecimal.ZERO: kwtLogistics.getEntrustAmount();
        BigDecimal subEntrustAmount = Objects.isNull(subtask.getEntrustAmount()) ? BigDecimal.ZERO: subtask.getEntrustAmount();
        KwtLogisticsOrder kwtLogisticsOrder = new KwtLogisticsOrder();
        kwtLogisticsOrder.setId(kwtLogistics.getId());
        BigDecimal subtractAmount = entrustAmount.subtract(subEntrustAmount);
        BigDecimal entrust = subtractAmount.compareTo(BigDecimal.ZERO) >= 0
                ? subtractAmount : new BigDecimal("0.00");
        kwtLogisticsOrder.setEntrustAmount(entrust);
       // kwtLogisticsOrder.setTotalLoadAmount(loadAmount.add(subLoadAmount));
        kwtLogisticsOrder.setTotalUnloadAmount(unloadAmount.add(subUnloadAmount));
        kwtLogistics.setTotalUnloadAmount(kwtLogisticsOrder.getTotalUnloadAmount());

        //如果审核的状态是 完成，那么就要去查询物流订单状态是完结中，并且所有物流订单下的运单全部是完成或者取消如果是则更新状态为已完成
        if (Objects.equals(kwtLogistics.getStatus(), LogisticsOrderV1Enum.NEARING_COMPLETION.getCode()) && Objects.equals(status,CarWaybillV1Enum.COMPLETED.getCode())){
            List<KwtWaybillOrderSubtask> waybillOrderSubtasks = kwtWaybillOrderSubtaskRepository.queryByLogId(subtask.getLOrderId());
            boolean b2 = waybillOrderSubtasks.stream()
               .allMatch(x -> Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode()).contains(x.getStatus()));
            if (b2){
                log.info("物流订单状态修改为已完成,物流订单id：{}", kwtLogistics.getId());
                kwtLogisticsOrder.setStatus(LogisticsOrderV1Enum.COMPLETED.getCode());
                kwtLogistics.setStatus(kwtLogisticsOrder.getStatus());
            }
        }
        return kwtLogisticsOrder;
    }

    public StatisticsWaybillResp statisticsWaybillOrder( WaybillOrderReq req) {

        log.info("运单状态统计：{}",JSON.toJSONString(req));
        StatisticsWaybillResp statisticsWaybillResp = new StatisticsWaybillResp();

        statisticsWaybillResp.setTotalNum("0");
        List<Integer> waybillOrderStatus = getWaybillOrderStatus();
        List<CarWaybillV1Enum> carWaybillV1Enums = Arrays.stream(CarWaybillV1Enum.values())
                .filter(x -> !waybillOrderStatus.contains(x.getCode()))
                .sorted(Comparator.comparing(CarWaybillV1Enum::getCode))
                .collect(Collectors.toList());

        Integer status = org.apache.commons.lang3.StringUtils.isNoneBlank(req.getStatus()) ?
                Integer.parseInt(req.getStatus()) : null;
      //  Set<Long> allEnt = getAllEnt(req);
        //物流订单号集合
        Set<Long> entIds = getEnterpriseIds(req);
        Long entId =LoginUserHolder.getEntId();
       // entIds.add(entId);
        log.debug("获取企业ID集合: {}", entIds);
        Set<Long> logOrderIds = getLogOrderIds(req, entIds,entId);
        // 应用数据权限过滤：个人数据权限与企业层级数据权限为并集关系
        logOrderIds = applyDataPermissionFilterToLogOrderIds(logOrderIds);
        boolean b1 = !org.apache.commons.lang3.StringUtils.isAllBlank(req.getLogisticsOrderNo(), req.getGoodsName(),
                req.getCarrierId(), req.getConsignorId()) || Objects.nonNull(entId);
        if(org.apache.commons.collections4.CollectionUtils.isEmpty(logOrderIds) && b1){
            Map<Integer, List<KwtWaybillOrderSubtask>> stausAndBillOrdersMap = Maps.newHashMap();
            List<StatisticsWaybillResp.OrderBillStatusStatistics> statusStatistics = carWaybillV1Enums.stream()
                    .map(c -> getOrderBillStatusStatistics(c, stausAndBillOrdersMap))
                    .collect(Collectors.toList());
            statisticsWaybillResp.setOrderStatusStatistics(statusStatistics);
            return statisticsWaybillResp;
        }
        //查询运单信息
        //运单id集合
        Set<Long> billOrderIds = getBillOrderIds(req);
        boolean b = Stream.of(req.getWaybillNo(), req.getTruckNo(), req.getDriverName(), req.getPhone(),
                        req.getLoadStartTime(),req.getLoadEndTime(),req.getUnloadStartTime(),req.getUnloadEndTime())
                .anyMatch(StringUtils::isNotBlank);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(billOrderIds) && b){
            Map<Integer, List<KwtWaybillOrderSubtask>> stausAndBillOrdersMap = Maps.newHashMap();
            List<StatisticsWaybillResp.OrderBillStatusStatistics> statusStatistics = carWaybillV1Enums.stream()
                    .map(c -> getOrderBillStatusStatistics(c, stausAndBillOrdersMap))
                    .collect(Collectors.toList());
            statisticsWaybillResp.setOrderStatusStatistics(statusStatistics);
            return statisticsWaybillResp;
        }

       // List<KwtWaybillOrder> orders = kwtWaybillOrderRepository.findList(status,billOrderIds,logOrderIds);
        //查询子运单
        List<KwtWaybillOrderSubtask> orders = kwtWaybillOrderSubtaskRepository.findByList(status,billOrderIds,logOrderIds);
        if (CollectionUtils.isEmpty(orders)) {
            Map<Integer, List<KwtWaybillOrderSubtask>> stausAndBillOrdersMap = Maps.newHashMap();
            List<StatisticsWaybillResp.OrderBillStatusStatistics> statusStatistics = carWaybillV1Enums.stream()
                    .map(c -> getOrderBillStatusStatistics(c, stausAndBillOrdersMap))
                    .collect(Collectors.toList());
            statisticsWaybillResp.setOrderStatusStatistics(statusStatistics);
            return statisticsWaybillResp;
        }
        Map<Integer,List<KwtWaybillOrderSubtask>> stausAndBillOrdersMap = orders.stream().collect(Collectors.groupingBy(KwtWaybillOrderSubtask::getStatus));
        List<StatisticsWaybillResp.OrderBillStatusStatistics> statusStatis = carWaybillV1Enums.stream()
                .map(c -> getOrderBillStatusStatistics(c, stausAndBillOrdersMap))
                .collect(Collectors.toList());
        statisticsWaybillResp.setOrderStatusStatistics(statusStatis);
        statisticsWaybillResp.setTotalNum(String.valueOf(orders.size()));
       return statisticsWaybillResp;
    }

    private List<Integer>  getWaybillOrderStatus() {
       return Arrays.asList( 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());
    }

    private static StatisticsWaybillResp.OrderBillStatusStatistics getOrderBillStatusStatistics(CarWaybillV1Enum c, Map<Integer, List<KwtWaybillOrderSubtask>> finalStausAndBillOrdersMap) {
        StatisticsWaybillResp.OrderBillStatusStatistics orderBillStatusStatistics = new StatisticsWaybillResp.OrderBillStatusStatistics();
        orderBillStatusStatistics.setOrderStatus(String.valueOf(c.getCode()));
        orderBillStatusStatistics.setOrderStatusDesc(c.getDestination());
        orderBillStatusStatistics.setOrderNum(String.valueOf(finalStausAndBillOrdersMap.getOrDefault(c.getCode(), new ArrayList<>()).size()));
        return orderBillStatusStatistics;
    }

    /**
     * 查询运单节点轨迹时间线
     *
     * @param req 请求参数
     * @return 节点轨迹列表
     * @author system
     * @date 2025/06/24
     */
    public WaybillOrderNodeVo queryWaybillOrderNodeTimeline(WaybillOrderNodeReq req) {
        log.info("查询运单节点轨迹，请求参数：{}", JSON.toJSONString(req));

        // 查询节点轨迹数据
        List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.queryNodesByOrderId(
                req.getWOrderId(), req.getWSubtaskId());

        if (CollectionUtils.isEmpty(nodes)) {
            return new WaybillOrderNodeVo();
        }

        // 转换为VO对象
        WaybillOrderNodeVo waybillOrderNodeVo = new WaybillOrderNodeVo();
        //获取时间线
        List<WaybillOrderNodeVo.Timeline> voList = getTimelines(nodes);
        waybillOrderNodeVo.setTimelines(voList);
        // 获取时间节点，并按前端五步序号排序（映射写入 orderStatus / orderStatusName）
        List<WaybillOrderNodeVo.WaybillOrderNode> nodeList = getWaybillOrderNodes(voList);
        log.info("查询运单节点轨迹，时间节点：{}", JSON.toJSONString(nodeList));
        // 按前端五步时间轴阶段去重，取满足状态中的最小原始状态对应时间
        nodeList = dedupeWaybillOrderNodesByStatus(nodeList);
        nodeList = nodeList.stream()
                .sorted(Comparator.comparing(WaybillOrderNodeVo.WaybillOrderNode::getOrderStatus))
                .collect(Collectors.toList());
        waybillOrderNodeVo.setWaybillOrderNodes(nodeList);
        return waybillOrderNodeVo;
    }

    @NotNull
    private List<WaybillOrderNodeVo.Timeline> getTimelines(List<KwtWaybillOrderNode> nodes) {
        List<WaybillOrderNodeVo.Timeline> voList = new ArrayList<>();
        for (KwtWaybillOrderNode node : nodes) {
            WaybillOrderNodeVo.Timeline vo = new WaybillOrderNodeVo.Timeline();
            //WaybillOrderNodeVo vo = new WaybillOrderNodeVo();
            vo.setId(node.getId());
            vo.setCreateTime(DateUtils.format(node.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
            vo.setOrderStatus(node.getOrderStatus());
            vo.setOrderStatusName(CarWaybillV1Enum.geDesc(node.getOrderStatus()));
            vo.setTruckNo(node.getTruckNo());
            vo.setDriverName(node.getDriverName());
            vo.setWeighbridgeName(node.getWeighbridgeName());
            vo.setLng(node.getLng());
            vo.setLat(node.getLat());
            vo.setHasWeighbridge(node.getWeighbridgeId() != null);
            vo.setImageUrl(node.getWeighUrl());
            if (Objects.equals(node.getOrderStatus(), CarWaybillV1Enum.COMPLETION_LOADING.getCode())){
                KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(node.getWOrderId());
                vo.setImageUrl(Optional.ofNullable(subtask).map(KwtWaybillOrderSubtask::getUnloadUrl).orElse(""));
            }

            // 构建状态描述
            //KwtWaybillOrderSubtask subtask = subtaskMap.get(node.getWSubtaskId());
           // String statusDesc = buildStatusDescription(node, subtask, goodsMap, unitMap);
            vo.setRemark(node.getRemark());

            // 构建地址信息
            String address = buildAddressFromLatLng(node.getLng(), node.getLat());
            vo.setAddress(address);

            voList.add(vo);
        }
        return voList;
    }

    @NotNull
    private static List<WaybillOrderNodeVo.WaybillOrderNode> getWaybillOrderNodes(List<WaybillOrderNodeVo.Timeline> voList) {
        Map<Integer, List<WaybillOrderNodeVo.Timeline>> statusAndTimelineMap = voList.stream()
                .filter(t ->!Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(),CarWaybillV1Enum.CANCELLED.getCode(), CarWaybillV1Enum.REVIEW_REJECTION.getCode()).contains(t.getOrderStatus()))
                .sorted(Comparator.comparing(WaybillOrderNodeVo.Timeline::getCreateTime))
                .collect(Collectors.groupingBy(WaybillOrderNodeVo.Timeline::getOrderStatus));
        List<WaybillOrderNodeVo.WaybillOrderNode> nodeList = Lists.newArrayList();
        statusAndTimelineMap.forEach((status, timelines) -> {
            WaybillOrderNodeVo.WaybillOrderNode waybillOrderNode = new WaybillOrderNodeVo.WaybillOrderNode();
            if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(timelines) && Objects.nonNull(timelines.get(0))){
                WaybillOrderNodeVo.Timeline timeline = timelines.get(0);
                waybillOrderNode.setId(timeline.getId());
                waybillOrderNode.setCreateTime(timeline.getCreateTime());
                waybillOrderNode.setOrderStatus(timeline.getOrderStatus());
                waybillOrderNode.setOrderStatusName(CarWaybillV1Enum.geDesc( timeline.getOrderStatus()));
                nodeList.add(waybillOrderNode);
            }
        });
        return nodeList;
    }

    /**
     * 将原始运单状态映射到前端五步时间轴，写入既有字段 {@code orderStatus}（1~5 阶段序号）、{@code orderStatusName}（阶段文案）；
     * 无法映射的节点保留 {@link #getWaybillOrderNodes} 中已赋值的原始码与描述。
     */
    private static void applyTimelinePhaseFromWaybillStatus(List<WaybillOrderNodeVo.WaybillOrderNode> nodeList) {
        if (CollectionUtils.isEmpty(nodeList)) {
            return;
        }
        for (WaybillOrderNodeVo.WaybillOrderNode node : nodeList) {
            WaybillTimelinePhaseEnum.resolve(node.getOrderStatus()).ifPresent(phase -> {
                node.setOrderStatus(phase.getPhaseOrder());
                node.setOrderStatusName(phase.getPhaseLabel());
            });
        }
    }

    /**
     * 映射后多个原始状态可能合并为同一阶段序号（1~5），会出现重复 {@code orderStatus}；
     * 按状态码去重，同一时间保留该阶段下 {@code createTime} 最早（第一次出现）的一条节点。
     */
    private static List<WaybillOrderNodeVo.WaybillOrderNode> dedupeWaybillOrderNodesByStatus(
            List<WaybillOrderNodeVo.WaybillOrderNode> nodeList) {
        if (CollectionUtils.isEmpty(nodeList)) {
            return nodeList;
        }
        return nodeList.stream()
                .filter(node -> Objects.nonNull(node.getOrderStatus()))
                .collect(Collectors.groupingBy(node -> WaybillTimelinePhaseEnum.resolve(node.getOrderStatus())
                        .map(WaybillTimelinePhaseEnum::getPhaseOrder)
                        .orElse(node.getOrderStatus())))
                .values()
                .stream()
                .map(KwtWaybillOrderV1Service::selectMinStatusEarliestNode)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 从同一前端时间轴阶段的节点列表中，筛选出用于展示的单一节点。
     * <p>
     * 处理逻辑：
     * 1. 找出列表中原始状态码（orderStatus）最小的节点集合（通常代表该阶段最早触发的业务状态）。
     * 2. 在最小状态码的节点中，选取创建时间（createTime）最早的一个节点。
     * 3. 将选中节点的 orderStatus 和 orderStatusName 映射为前端时间轴所需的阶段序号和阶段名称。
     * </p>
     *
     * @param nodes 属于同一前端展示阶段的运单节点列表
     * @return 筛选后的单个节点对象，若列表为空或无有效数据则返回 null
     */
    private static WaybillOrderNodeVo.WaybillOrderNode selectMinStatusEarliestNode(
            List<WaybillOrderNodeVo.WaybillOrderNode> nodes) {
        // 1. 空值校验
        if (CollectionUtils.isEmpty(nodes)) {
            log.debug("selectMinStatusEarliestNode: 节点列表为空，返回 null");
            return null;
        }

        // 2. 提取最小原始状态码
        // 在同一阶段映射下，可能存在多个原始业务状态，取数值最小的作为基准（通常代表初始状态）
        Integer minStatus = nodes.stream()
                .map(WaybillOrderNodeVo.WaybillOrderNode::getOrderStatus)
                .filter(Objects::nonNull)
                .min(Integer::compareTo)
                .orElse(null);

        if (Objects.isNull(minStatus)) {
            log.warn("selectMinStatusEarliestNode: 无法从节点列表中提取有效的最小状态码，节点数量: {}", nodes.size());
            return null;
        }
        log.debug("selectMinStatusEarliestNode: 提取到最小状态码: {}", minStatus);

        // 3. 筛选具有最小状态码且创建时间最早的节点
        WaybillOrderNodeVo.WaybillOrderNode selected = nodes.stream()
                .filter(node -> Objects.equals(node.getOrderStatus(), minStatus))
                .min(Comparator.comparing(node -> parseWaybillNodeCreateTime(node.getCreateTime())))
                .orElse(null);

        if (Objects.isNull(selected)) {
            log.warn("selectMinStatusEarliestNode: 状态码为 {} 的节点中未找到有效创建时间的节点", minStatus);
            return null;
        }
        log.debug("selectMinStatusEarliestNode: 选中节点 ID: {}, 状态: {}, 创建时间: {}",
                selected.getId(), selected.getOrderStatus(), selected.getCreateTime());

        // 4. 映射前端时间轴阶段信息
        // 将原始业务状态转换为前端展示用的阶段序号（phaseOrder）和阶段名称（phaseLabel）
        WaybillTimelinePhaseEnum.resolve(minStatus).ifPresent(phase -> {
            log.debug("selectMinStatusEarliestNode: 映射前端阶段，原始状态: {} -> 阶段序号: {}, 阶段名称: {}",
                    minStatus, phase.getPhaseOrder(), phase.getPhaseLabel());
            selected.setOrderStatus(phase.getPhaseOrder());
            selected.setOrderStatusName(phase.getPhaseLabel());
        });

        return selected;
    }

    private static Date parseWaybillNodeCreateTime(String createTime) {
        if (org.apache.commons.lang3.StringUtils.isBlank(createTime)) {
            return new Date(0L);
        }
        Date d = DateUtils.formatDate(createTime);
        return d != null ? d : new Date(0L);
    }

    /**
     * 构建状态描述文本
     * 格式：车辆【川A5478C】司机【张三】装载货物【铁矿石】【参运】【28.70吨】
     */
    private String buildStatusDescription(KwtWaybillOrderNode node,
                                          KwtWaybillOrderSubtask subtask,
                                          Map<Long, KwtLogisticsOrderGoods> goodsMap,
                                          Map<String, String> unitMap) {
        if (Objects.isNull(subtask)){
            return "";
        }
        StringBuilder sb = new StringBuilder();

        if (Objects.equals(node.getOrderStatus(), CarWaybillV1Enum.PENDING_VEHICLE.getCode())) {
            sb.append(" 车辆【").append(node.getTruckNo()).append("】");
            sb.append(" 司机【").append(node.getDriverName()).append("】接单成功");
            sb.append(" 预计任务重量【").append(subtask.getEntrustAmount()).append(subtask.getUnit()).append("】");
        }

        if (Objects.equals(node.getOrderStatus(), CarWaybillV1Enum.REFUSE_TRAFFIC.getCode())) {
            sb.append(" 已到达装货点,").append(node.getWeighbridgeName()).append("】").append(subtask.getEntrustAmount()).append(subtask.getUnit());
        }
        if (Objects.equals(node.getOrderStatus(), CarWaybillV1Enum.EXIT_COMPLETED.getCode())) {
            sb.append(" 装货完成,").append(node.getTruckNo()).append(node.getDriverName());
            sb.append(node.getWeighbridgeName()).append("称重").append(subtask.getLoadAmount());
        }

        if (Objects.equals(node.getOrderStatus(), CarWaybillV1Enum.WAIT_LOADING.getCode())) {
            sb.append(" 司机【").append(node.getDriverName()).append("】已确认离场");
        }
        return sb.toString();
    }

    /**
     * 根据状态获取标签
     */
    private String getStatusLabel(Integer status) {
        if (status == null) {
            return "";
        }
        // 根据具体业务逻辑返回标签，如：参运、实装、实卸等
        // CarWaybillV1Enum: 1-已接单, 5-到达装货点, 10-已装货, 15-已离场, 20-已卸货, 25-已完成, 30-审核驳回, 99-已取消
        if (status.equals(CarWaybillV1Enum.EXIT_COMPLETED.getCode())) {
            // 10-已装货
            return "实装";
        } else if (status.equals(CarWaybillV1Enum.COMPLETION_LOADING.getCode())) {
            // 20-已卸货
            return "实卸";
        } else if (status.equals(CarWaybillV1Enum.WAIT_LOADING.getCode())) {
            // 15-已离场
            return "参运";
        }
        return "";
    }

    /**
     * 根据状态获取对应的重量
     */
    private String getWeightByStatus(Integer status, KwtWaybillOrderSubtask subtask) {
        if (status == null || subtask == null) {
            return "";
        }

        // 根据状态返回不同的重量
        // CarWaybillV1Enum: 1-已接单, 5-到达装货点, 10-已装货, 15-已离场, 20-已卸货, 25-已完成, 30-审核驳回, 99-已取消
        if (status.equals(CarWaybillV1Enum.WAIT_LOADING.getCode())) {
            // 15-已离场-参运显示委托量
            return String.valueOf(subtask.getEntrustAmount());
        } else if (status.equals(CarWaybillV1Enum.EXIT_COMPLETED.getCode())) {
            // 10-已装货-装货显示实装量
            return String.valueOf(subtask.getLoadAmount());
        } else if (status.equals(CarWaybillV1Enum.COMPLETION_LOADING.getCode())) {
            // 20-已卸货-卸货显示实卸量
            return String.valueOf(subtask.getUnloadAmount());
        }

        return "";
    }

    /**
     * 根据经纬度构建地址信息
     * 实际项目中可以调用地图服务API进行逆地理编码
     */
    private String buildAddressFromLatLng(String lng, String lat) {
        if (StringUtils.isBlank(lng) || StringUtils.isBlank(lat)) {
            return "";
        }
        // 这里可以调用高德/百度等地图API进行逆地理编码
        // 暂时返回经纬度格式
        return String.format("经度:%s, 纬度:%s", lng, lat);
    }

    /**
     * 根据运单号模糊查询运单ID和运单号列表
     *
     * @param wOrderNo 运单号关键字（模糊匹配）
     * @return 运单列表
     */
    public List<WaybillOrderSimpleVo> queryWaybillOrderListByWOrderNo(String wOrderNo) {
        // 查询运单数据
        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryWaybillOrderListByWOrderNo(wOrderNo);

        // 转换为VO
        return waybillOrders.stream()
                .map(order -> {
                    WaybillOrderSimpleVo vo = new WaybillOrderSimpleVo();
                    vo.setId(order.getId());
                    vo.setWOrderNo(order.getWOrderNo());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 查询运单车辆ID和车牌号列表（去重）
     *
     * @return 车辆列表
     */
    public List<WaybillOrderTruckVo> queryTruckList() {
        Long entId = LoginUserHolder.getEntId();
        // 查询运单车辆数据
        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryTruckList(entId);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(waybillOrders)){
            return List.of();
        }
        // 转换为VO
        return waybillOrders.stream()
                .map(order -> {
                    WaybillOrderTruckVo vo = new WaybillOrderTruckVo();
                    vo.setTruckId(order.getTruckId());
                    vo.setTruckNo(order.getTruckNo());
                    return vo;
                })
                .collect(Collectors.toList());
    }
}
