package com.sckw.transport.service;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
import com.sckw.core.model.constant.UrlConstants;
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.HttpResult;
import com.sckw.excel.utils.DateUtil;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.fleet.api.model.vo.*;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
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.model.dto.res.*;
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.ApproveStatusEnum;
import com.sckw.transport.model.enuma.CarWaybillDetailEnum;
import com.sckw.transport.model.enuma.CarWaybillNdexTopEnum;
import com.sckw.transport.model.enuma.CarWaybillTableTopEnum;
import com.sckw.transport.model.vo.*;
import com.sckw.transport.repository.KwtWaybillOrderAddressRepository;
import com.sckw.transport.repository.KwtWaybillOrderTrackRepository;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
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.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
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;
    @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)
    private RemoteFleetService remoteFleetService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TradeOrderInfoService tradeOrderInfoService;
    @Value("${message.waybill.refuseSendCar.app}")
    private String refuseSendCarAppUrl;
    @Value("${message.waybill.refuseSendCar.pc}")
    private String refuseSendCarPcUrl;

    /**
     * @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) {
                waybillOrder.setActualWeight(truck.getActualWeight());
            }
        }
        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);
                //地址id映射运单状态
                Map<Long, KwtWaybillOrderTrack> addressIdAndTrackMap = tracks.stream()
                        .collect(Collectors.toMap(KwtWaybillOrderTrack::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->{
                    KwtWaybillOrderTrack 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());
                String s = "";
                try {
                    s = HttpUtil.postJson(urlConfigProperties.getApiBaseUrl()+ UrlConstants.QUERY_TRACE_URL, com.alibaba.fastjson.JSON.toJSONString(vehicleDataDTO), null);
                } catch (Exception e) {
                    log.error("查询任务轨迹异常",e);

                }
                if (org.apache.commons.lang3.StringUtils.isNotBlank(s)){
                    List<VehicleRouteData> vehicleReturnData = com.alibaba.fastjson.JSON.parseArray(s, VehicleRouteData.class);
                    rTruckRouteVo.setPointInfo(com.alibaba.fastjson.JSON.toJSONString(vehicleReturnData));
                }

                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;
    }
}
