package com.sckw.fleet.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.vo.KwcContractLogisticsDto;
import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
import com.sckw.core.common.enums.enums.FileEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.BusinessPlatfromException;
import com.sckw.core.exception.SystemException;
import com.sckw.core.model.base.BaseModel;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.SystemTypeEnum;
import com.sckw.core.model.file.FileInfo;
import com.sckw.core.utils.*;
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.easyexcel.ExcelImportListener;
import com.sckw.excel.utils.ExcelUtil;
import com.sckw.file.api.dubbo.FileApiDubboService;
import com.sckw.fleet.dao.*;
import com.sckw.fleet.model.*;
import com.sckw.fleet.model.dto.*;
import com.sckw.fleet.model.request.AssociatedTrackAddRequest;
import com.sckw.fleet.model.request.AssociatedTrackRequest;
import com.sckw.fleet.model.request.DriverAssociatedTruckSaveRequest;
import com.sckw.fleet.model.request.TruckSaveParam;
import com.sckw.fleet.model.vo.*;
import com.sckw.fleet.repository.*;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.RemoteUserService;
import com.sckw.system.api.model.dto.req.KwsUserReqDto;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportRemoteService;
import com.sckw.transport.api.model.param.CapacityTruckParam;
import com.sckw.transport.api.model.vo.RWaybillOrderVo;
import com.sckw.transport.api.model.vo.WaybillOrderTaskVO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @desc 司机
 * @author zk
 * @date 2023/7/6 0006
 */
@Slf4j
@Service
@SuppressWarnings("all")
@Transactional(rollbackFor = Exception.class)
public class KwfDriverService {

    @Autowired
    KwfDriverMapper driverDao;
    @Autowired
    KwfDriverEntMapper driverEntDao;
    @Autowired
    KwfDriverCardMapper KwfDriverCardDao;
    @Autowired
    KwfDriverLicenseMapper KwfDriverLicenseDao;
    @Autowired
    KwfDriverQualificationMapper KwfDriverQualificationDao;
    @Autowired
    KwfDriverImportMapper kwfDriverImportDao;
    @Autowired
    KwfTruckReportMapper truckReportDao;
    @Autowired
    KwfFleetDriverMapper fleetDriverDao;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private FileApiDubboService remoteFileService;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    private RemoteUserService remoteUserService;
    @Autowired
    KwfTruckReportRepository truckReportRepository;
    @Autowired
    KwfTruckRepository truckRepository;
    @Autowired
    KwfDriverAssociatedTruckRepository driverAssociatedTruckRepository;
    @Autowired
    KwfDriverScoreRepository driverScoreRepository;
    @Autowired
    KwfDriverScoreDetailRepository driverScoreDetailRepository;

    @Autowired
    KwfTruckAxleNumRepository truckAxleNumRepository;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    private TransportRemoteService transportRemoteService;
    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
    private RemoteContractService remoteContractService;

    @Autowired
    private KwfDriverMapper driverMapper;
    @Autowired
    KwfTruckService truckService;

    /**
     * @param key 逐渐id
     * @desc 根据主键查询
     * @author zk
     * @date 2023/7/6
     **/
    public KwfDriver selectByKey(Long key) {
        return driverDao.selectById(key);
    }

    /**
     * @param driverId 司机ID
     * @desc 司机信息查询
     * @author zk
     * @date 2023/7/11
     **/
    public KwfDriverDetailVo detail(Long driverId) {
        //司机信息
        KwfDriver driver = this.selectByKey(driverId);
        KwfDriverDetailVo driverDetailVo = new KwfDriverDetailVo();
        BeanUtils.copyPropertiesValue(driver, driverDetailVo);

        //数据查询
        if (driver != null) {
            //身份证信息
            KwfDriverCard cardJson = this.findCarByKey(driverId);
            KwfDriverCardVo driverCardVo = new KwfDriverCardVo();
            BeanUtils.copyPropertiesValue(cardJson, driverCardVo);
            driverDetailVo.setDriverCard(driverCardVo);

            //司机驾驶证信息
            KwfDriverLicense licenseJson = this.findLicenseByKey(driverId);
            KwfDriverLicenseVo driverLicenseVo = new KwfDriverLicenseVo();
            BeanUtils.copyPropertiesValue(licenseJson, driverLicenseVo);
            String value = getDictValue(DictTypeEnum.APPROVED_DRIVING.getType(), driverLicenseVo.getType());
            driverLicenseVo.setTypeName(value);
            driverDetailVo.setDriverLicense(driverLicenseVo);

            //司机从业资格证
            KwfDriverQualification qualificationJson = this.findQualificationByKey(driverId);
            KwfDriverQualificationVo qualificationVo = new KwfDriverQualificationVo();
            BeanUtils.copyPropertiesValue(qualificationJson, qualificationVo);
            value = getDictValue(DictTypeEnum.APPROVED_DRIVING.getType(), qualificationVo.getType());
            qualificationVo.setTypeName(value);
            driverDetailVo.setDriverQualification(qualificationVo);

//            //车队班组
//            KwfFleet fleet = this.findByFleetDriver(driverId, LoginUserHolder.getEntId());
//            driverDetailVo.setFleetId(fleet != null ? fleet.getId() : null);
//            driverDetailVo.setFleetName(fleet != null ? fleet.getName() : null);

            //司机关联车辆（车辆上报）
            if (LoginUserHolder.getSystemType() == SystemTypeEnum.DRIVER.getCode()) {
                List<Map<String, Object>> trucks = new ArrayList();
                List<Map<String, Object>> reports = truckReportDao.findList(new HashMap() {{
                    put("driverId", driverId);
                }});
                for (Map<String, Object> report : reports) {
                    trucks.add(new HashMap() {{
                        put("truckId", report.get("truckId"));
                        put("truckNo", report.get("truckNo"));
                        put("trailerNo", report.get("truckTrailerNo"));
                        put("authStatus", report.get("authStatus"));
                    }});
                }
                driverDetailVo.setTrucks(trucks.stream().distinct().collect(Collectors.toList()));
            }
            return driverDetailVo;
        }
        return null;
    }

    /**
     * @param params 参数
     * @desc 统计
     * @author zk
     * @date 2023/7/11
     **/
    public Map statistics(Map<String, Object> params) {
        /**统计数据**/
        List<KwfTableTopCount> counts = this.statisticsHandle(params);
        long tatol = 0;
        for (KwfTableTopCount topCount:counts) {
            tatol += topCount.getTotal();
        }

        /**全部数据-处理**/
        List<KwfTableTopCount> countList = new ArrayList();
        KwfTableTopCount allCount = new KwfTableTopCount();
        allCount.setValue(String.valueOf(Global.NUMERICAL_ZERO));
        allCount.setTotal(tatol);
        allCount.setName("全部");
        countList.add(allCount);

        /**数据处理**/
        Map<String, Integer> authStatusMap = new HashMap(){{put("正常", 1); put("临时", 2); put("异常", 3);}};
        for(Map.Entry<String, Integer> entry:authStatusMap.entrySet()){
            KwfTableTopCount count = new KwfTableTopCount();
            for (KwfTableTopCount topCount:counts) {
                if (Integer.parseInt(topCount.getValue()) == entry.getValue()) {
                    BeanUtils.copyProperties(topCount, count);
                }
            }
            count.setName(entry.getKey());
            count.setValue(String.valueOf(entry.getValue()));
            countList.add(count);
        }

        /**数据组装**/
        Map tableCount = new HashMap();
        tableCount.put("tableTop", countList);
        tableCount.put("tableBottom", tatol);
        return tableCount;
    }

    /**
     * @param params 参数
     * @desc 统计
     * @author zk
     * @date 2023/9/11
     **/
    public List<KwfTableTopCount> statisticsHandle(Map<String, Object> params) {
        int systemType = LoginUserHolder.getSystemType();
        /**统计数据**/
        if (systemType == SystemTypeEnum.MANAGE.getCode()) {
            //新增客户经理权限过滤
            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);
            }
            List<KwfTableTopCount> counts = driverDao.statisticsAll(params,authEntIdList);
            return counts;
        } else {
            params.put("entId", LoginUserHolder.getEntId());
            List<KwfTableTopCount> counts = driverDao.statistics(params);
            return counts;
        }
    }

    /**
     * @param params 分页参数
     * @desc 分页查询
     * @author zk
     * @date 2023/7/6
     **/
    public List<KwfDriverVo> findPage(Map<String, Object> params) {
        /**查询分页数据**/
        List<KwfDriverVo> drivers = this.findPageHandle(params);
        if (CollectionUtils.isEmpty(drivers)) {
            return drivers;
        }

        /**获取查询数据**/
        List<Long> createBys = new ArrayList<>();
        List<Long> entIds = new ArrayList<>();
        List<String> dictKey = new ArrayList<>();
        for (KwfDriverVo driver:drivers) {
            createBys.add(Long.parseLong(driver.getCreateBy()));
            entIds.add(Long.parseLong(driver.getEntId()));
            dictKey.add(StringUtils.isNotBlank(driver.getLicenseType())
                    ? DictTypeEnum.APPROVED_DRIVING.getType() + Global.POUND + driver.getLicenseType() : null);
        }
        //用户数据集
        createBys = createBys.stream().distinct().collect(Collectors.toList());
        Map<Long, UserCacheResDto> users = remoteSystemService.queryUserCacheMapByIds(createBys);
        //企业数据集
        entIds = entIds.stream().distinct().collect(Collectors.toList());
        Map<Long, EntCacheResDto> ents = remoteSystemService.queryEntCacheMapByIds(entIds);
        //数据字典
        Map<String, SysDictResDto> dicts = this.dict(dictKey);

        /**数据组装**/
        for (KwfDriverVo driver : drivers) {
            UserCacheResDto user = users == null ? null : users.get(Long.parseLong(driver.getCreateBy()));
            EntCacheResDto ent = ents == null ? null : ents.get(Long.parseLong(driver.getEntId()));
            SysDictResDto licenseType = dicts == null
                    ? null : dicts.get(DictTypeEnum.APPROVED_DRIVING.getType() + Global.POUND + driver.getLicenseType());
            driver.setCreateByName(user != null ? user.getName() : null);
            driver.setFirmName(ent != null ? ent.getFirmName() : null);
            driver.setLicenseTypeName(licenseType != null ? licenseType.getLabel() : null);

            //获取车辆信息
            KwfTruck truckInfo = getTruckInfo(driver.getId(), driver.getEntId());
            driver.setTruckNo(truckInfo.getTruckNo());

            //获取司机完成量(查询司机的当天完成量、7天完成量、30天完成量)
            getDriverTaskAmounts(driver.getEntId(), driver.getId(), driver);

            //获取司机评分
            getDriverScore(driver.getEntId(), driver.getId(), driver);

        }
        return drivers;
    }

    /**
     * @param params 分页参数
     * @desc 分页查询
     * @author zk
     * @date 2023/9/11
     **/
    public List<KwfDriverVo> findPageHandle(Map<String, Object> params) {
        int systemType = LoginUserHolder.getSystemType();
        /**统计数据**/
        if (systemType == SystemTypeEnum.MANAGE.getCode()) {
            //新增客户经理权限过滤
            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);
            }
            List<KwfDriverVo> drivers = driverDao.findPageAll(params,authEntIdList);
            return drivers;
        } else {
            params.put("entId", LoginUserHolder.getEntId());
            List<KwfDriverVo> drivers = driverDao.findPage(params);
            return drivers;
        }
    }

    /**
     * 根据司机id和企业id查询车辆信息
     *
     * @param truck
     * @param ents
     * @return
     */
    private KwfTruck getTruckInfo(String driverId, String entId) {
        //查询司机关联车辆信息
        KwfTruckReport truckReport = truckReportRepository.getOne(Wrappers.<KwfTruckReport>lambdaQuery()
                .eq(BaseModel::getDelFlag, 0)
                .eq(BaseModel::getStatus, 1)
                .eq(KwfTruckReport::getDriverId, driverId)
                .eq(KwfTruckReport::getEntId, entId));
        if (truckReport == null) {
            return new KwfTruck();
        }

        //查询车辆信息
        KwfTruck truck = truckRepository.getOne(Wrappers.<KwfTruck>lambdaQuery()
                .eq(BaseModel::getDelFlag, 0)
                .eq(KwfTruck::getId, truckReport.getTruckId()));
        if (truck == null) {
            return new KwfTruck();
        }
        return truck;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveTruckAndAssociate(DriverAssociatedTruckSaveRequest request) {
        log.info("开始新增车辆档案并关联司机，request={}", JSON.toJSONString(request));
        
        String entId = request.getEntId();
        if (org.apache.commons.lang3.StringUtils.isBlank(entId)) {
            log.error("新增车辆档案失败：企业id不能为空");
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "企业id不能为空");
        }

        // 构建车辆保存参数
        TruckSaveParam truckSaveParam = new TruckSaveParam();
        truckSaveParam.setTruckNo(request.getTruckNo());
        truckSaveParam.setType(request.getType());
        truckSaveParam.setCarAxis(String.valueOf(request.getTruckAxleId()));
        truckSaveParam.setEnergyType(request.getEnergyType());
        truckSaveParam.setEev(request.getEev());
        truckSaveParam.setEngineNo(request.getEngineNo());
        truckSaveParam.setTruckLicense(request.getTruckLicense());
        truckSaveParam.setTransportLicense(request.getTransportLicense());
        truckSaveParam.setEnvironmentalList(request.getEnvironmentalList());
        truckSaveParam.setFleetId(request.getFleetId());
        truckSaveParam.setVin(request.getVin());
        truckSaveParam.setBrand(request.getBrand());
        truckSaveParam.setPositionDevice(request.getPositionDevice());
        truckSaveParam.setEntId(StringUtils.isNotBlank(entId) ? Long.valueOf(entId) : LoginUserHolder.getEntId());
        
        log.info("调用truckService.saveTruck保存车辆档案，truckNo={}", request.getTruckNo());
        try {
            truckService.saveTruck1(truckSaveParam);
            log.info("车辆档案保存成功，truckNo={}", request.getTruckNo());
        } catch (Exception e) {
            log.error("车辆档案保存异常，truckNo={}", request.getTruckNo(), e);
            throw new BusinessException("车辆档案保存异常");
        }

        // 查询刚保存的车辆信息
        log.info("查询刚保存的车辆信息，truckNo={}", request.getTruckNo());
        KwfTruck truck = truckRepository.getOne(Wrappers.<KwfTruck>lambdaQuery()
                .eq(KwfTruck::getTruckNo, request.getTruckNo())
                .last("limit 1"));
        
        if (truck == null) {
            log.error("车辆档案保存后查询失败，truckNo={}", request.getTruckNo());
            throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_NOT_FOUND, "车辆档案保存失败");
        }
        log.info("查询车辆信息成功，truckId={}, truckNo={}", truck.getId(), truck.getTruckNo());

        // 构建关联请求并执行关联
        AssociatedTrackAddRequest associatedTrackAddRequest = new AssociatedTrackAddRequest();
        associatedTrackAddRequest.setEntId(Long.valueOf(entId));
        associatedTrackAddRequest.setDriverId(request.getDriverId());
        associatedTrackAddRequest.setTruckNo(truck.getTruckNo());
        associatedTrackAddRequest.setTruckAxleId(request.getTruckAxleId());
        
        log.info("开始关联司机与车辆，driverId={}, truckNo={}", request.getDriverId(), truck.getTruckNo());
        try {
            addAssociatedTrack(associatedTrackAddRequest);
            log.info("司机与车辆关联成功，driverId={}, truckNo={}", request.getDriverId(), truck.getTruckNo());
        } catch (Exception e) {
            log.error("司机与车辆关联异常，driverId={}, truckNo={}", request.getDriverId(), truck.getTruckNo(), e);
            throw new BusinessException( "司机与车辆关联异常");
        }
        
        log.info("新增车辆档案并关联司机流程结束");
    }

    /**
     * 查询司机的当天完成量、7天完成量、30天完成量
     *
     * @param truck
     * @param ents
     * @return
     */
    private void getDriverTaskAmounts(String entId, String driverId, KwfDriverVo driver) {
        if (StringUtils.isEmpty(entId) || StringUtils.isEmpty(driverId)) {
            return;
        }
        //查询司机的当天完成量、7天完成量、30天完成量
        WaybillOrderTaskVO taskVO = transportRemoteService.queryWaybillOrderTaskByDriverId(Long.valueOf(entId), Long.valueOf(driverId));
        if (taskVO == null) {
            return;
        }
        driver.setTodayTaskAmount(taskVO.getTodayTaskAmount());
        driver.setWeeklyTaskAmount(taskVO.getWeeklyTaskAmount());
        driver.setMonthlyTaskAmount(taskVO.getMonthlyTaskAmount());
    }

    /**
     * 司机评分
     *
     * @param truck
     * @param ents
     * @return
     */
    private void getDriverScore(String entId, String driverId, KwfDriverVo driver) {
//        if (true) {
//            return; //TODO 开关
//        }

        if (StringUtils.isEmpty(entId) || StringUtils.isEmpty(driverId)) {
            return;
        }
        //查询当前物流企业自动派单且生效的物流合同
        KwcContractLogisticsDto logContractByEntId = remoteContractService.findLogContractByEntId(Long.valueOf(entId));
        if (logContractByEntId == null || logContractByEntId.getSupEntId() == null) {
            return;
        }

        //司机评分
        KwfDriverScore driverScoreByEntIds = driverScoreRepository.findDriverScoreByEntIds(Long.valueOf(logContractByEntId.getSupEntId()), Long.valueOf(entId), Long.valueOf(driverId));
        if (driverScoreByEntIds == null) {
            return;
        }
        driver.setScoreId(driverScoreByEntIds.getId());
        driver.setScore(driverScoreByEntIds.getScore());
    }

        /**
         * @param params 查询参数
         * @desc 查询
         * @author zk
         * @date 2023/7/6
         **/
    public List<Map<String, Object>> findList(Map<String, Object> params) {
        return driverDao.findList(params);
    }

    /**
     * @param {}
     * @description 导出
     * @author zk
     * @date 2023/07/11
     **/
    public HttpResult importExcel(MultipartFile file) {
        /**文件存储**/
        importFileSave(file);

        /**参数校验**/
        HttpResult result = this.checkParams(file);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }

        /**数据处理**/
        int count = 0;
        List<KwfDriverExcelImportDto> driverExcels = (List)result.getData();
        for (KwfDriverExcelImportDto driverExcel:driverExcels) {
            //司机信息
            KwfDriver driver = new KwfDriver();
            driver.setName(driverExcel.getName());
            driver.setPhone(driverExcel.getPhone());
            driver.setIdcard(driverExcel.getIdcard());
            driver.setAuthStatus(Global.NUMERICAL_TWO);
            result = driverEdit(driver);
            if (result.getCode() == HttpStatus.SUCCESS_CODE) {
                count ++;
            }
        }

        return HttpResult.ok("成功导入"+count+"行数据！");
    }

    /**
     * @param params 参数
     * @desc 新增司机（Seata 全局事务：车队库 + 远程 system 用户/角色库一致提交或回滚，需 Seata TC 与各服务数据源代理已就绪）
     * @author zk
     * @date 2023/7/6
     **/
    @Transactional(rollbackFor = Exception.class)
    public HttpResult add(KwfDriverDto params) {
        /**司机信息**/
        KwfDriver driver = new KwfDriver();
        BeanUtils.copyProperties(params, driver);
        //证件都有数据则为已认证(前端校验认证数据必填)
        boolean bool = checkLicense(params);
        if (bool) {
            driver.setAuthStatus(Global.NUMERICAL_ONE);
        } else {
            driver.setAuthStatus(Global.NUMERICAL_TWO);
        }
        HttpResult result = driverEdit(driver);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }
        driver = (KwfDriver)result.getData();

        /**身份证信息**/
        KwfDriverCardDto driverCardDto = params.getDriverCard();
        if (driverCardDto != null) {
            driverCardDto.setDriverId(driver.getId());
            requireBizSuccess(driverCardEdit(driverCardDto), "身份证信息");
        }

        /**司机驾驶证信息**/
        KwfDriverLicenseDto driverLicenseDto = params.getDriverLicense();
        if (driverLicenseDto != null) {
            driverLicenseDto.setDriverId(driver.getId());
            requireBizSuccess(driverLicenseEdit(driverLicenseDto), "驾驶证信息");
        }

        /**司机从业资格证**/
        KwfDriverQualificationDto driverQualificationDto = params.getDriverQualification();
        if (driverQualificationDto != null) {
            driverQualificationDto.setDriverId(driver.getId());
            requireBizSuccess(driverQualificationEdit(driverQualificationDto), "从业资格证信息");
        }

        /**车队班组绑定**/
        requireBizSuccess(driverFleetEdit(driver.getId(), params.getFleetId()), "车队班组绑定");
        //同步信息到员工列表（system 服务，参与同一全局事务）
        params.setDriverId(driver.getId());
        userEdit(params);
        return HttpResult.ok(result.getMsg(), driver);
    }

    /**
     * 全局事务下子步骤若仅用 {@link HttpResult} 表示失败而不抛异常，TM 仍会提交；失败时必须抛异常以驱动回滚。
     */
    private void requireBizSuccess(HttpResult result, String stepName) {
        if (result == null || result.getCode() != HttpStatus.SUCCESS_CODE) {
            String detail = result != null ? result.getMsg() : "未返回结果";
            throw new SystemException(
                    result != null ? result.getCode() : HttpStatus.CRUD_FAIL_CODE,
                    stepName + "失败：" + detail);
        }
    }

    private void userEdit(KwfDriverDto params) {
        KwsUserReqDto kwsUserReqDto = new KwsUserReqDto();
        //密码为空时，以登录名作为密码
        String salt = PasswordUtils.generateSalt();
        kwsUserReqDto.setSystemType(LoginUserHolder.getSystemType());
        kwsUserReqDto.setEntId(LoginUserHolder.getEntId());
        kwsUserReqDto.setAccount(params.getPhone());
        String password  =  PasswordUtils.entryptPassword(params.getPhone() + PasswordUtils.md5(params.getPhone()), salt);
        kwsUserReqDto.setPassword(password);
        kwsUserReqDto.setName(params.getName());
        kwsUserReqDto.setPhone(params.getPhone());
        kwsUserReqDto.setPhoto("");
        kwsUserReqDto.setEmail("");
        kwsUserReqDto.setClientId("");
        kwsUserReqDto.setIsMain(0);
        kwsUserReqDto.setSalt(salt);
        kwsUserReqDto.setRemark("司机管理");
        kwsUserReqDto.setStatus(0);
        kwsUserReqDto.setCreateBy(LoginUserHolder.getUserId());
        Date date = new Date();
        kwsUserReqDto.setCreateTime(date);
        kwsUserReqDto.setUpdateBy(LoginUserHolder.getUserId());
        kwsUserReqDto.setUpdateTime(date);
        kwsUserReqDto.setDelFlag(0);
        kwsUserReqDto.setDriverId(params.getDriverId());
        remoteUserService.saveUser(kwsUserReqDto);
    }

    /**
     * @param params 参数
     * @desc 修改司机
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult update(KwfDriverDto params) {
        /**数据校验**/
        if (StringUtils.isBlank(params.getId())) {
            return HttpResult.error(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE,"司机信息ID不能为空！");
        }
        KwfDriver driver = driverDao.selectById(params.getId());
        if (driver == null) {
            return HttpResult.error("司机信息不存在！");
        }

        /**司机信息**/
        BeanUtils.copyProperties(params, driver);
        //证件都有数据则为已认证(前端校验认证数据必填)
        boolean bool = checkLicense(params);
        if (bool) {
            driver.setAuthStatus(Global.NUMERICAL_ONE);
        }
        HttpResult result = driverEdit(driver);
        if (result.getCode() != HttpStatus.SUCCESS_CODE) {
            return result;
        }

        /**身份证信息**/
        KwfDriverCardDto driverCardDto = params.getDriverCard();
        if (driverCardDto != null) {
            driverCardDto.setDriverId(driver.getId());
            driverCardEdit(driverCardDto);
        }

        /**司机驾驶证信息**/
        KwfDriverLicenseDto driverLicenseDto = params.getDriverLicense();
        if (driverLicenseDto != null) {
            driverLicenseDto.setDriverId(driver.getId());
            driverLicenseEdit(driverLicenseDto);
        }

        /**司机从业资格证**/
        KwfDriverQualificationDto driverQualificationDto = params.getDriverQualification();
        if (driverQualificationDto != null) {
            driverQualificationDto.setDriverId(driver.getId());
            driverQualificationEdit(driverQualificationDto);
        }

        /**车队班组绑定**/
//        driverFleetEdit(driver.getId(), params.getFleetId());

        return HttpResult.ok(result.getMsg());
    }

    /**
     * @param {ids：主键ID（多个以逗号隔开）}
     * @description 删除
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult del(String ids) {
        /**数据校验**/
        if (StringUtils.isBlank(ids)) {
            return HttpResult.error("请选择要删除的数据！");
        }

        /**数据组装**/
        String[] idArray = ids.split(",");
        KwfDriverEnt driverEntQuery = new KwfDriverEnt();
        driverEntQuery.setEntId(LoginUserHolder.getEntId());
        for (String id : idArray) {
            driverEntQuery.setDriverId(Long.parseLong(id));
            KwfDriverEnt driverEnt = driverEntDao.findByDriverEnt(driverEntQuery);
            if (driverEnt != null) {
                driverEnt.setDelFlag(Global.YES);
                if (driverEntDao.updateById(driverEnt) <= 0) {
                    throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.DELETE_FAIL);
                }
            } else {
                return HttpResult.error("选择删除的数据已不存在！");
            }
        }
        return HttpResult.ok("删除成功！");
    }

    /**
     * @param params 参数
     * @desc 新增司机信息
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult driverEdit(KwfDriver params) {
        if (StringUtils.isBlank(params.getId())) {
            /**唯一性交易**/
            List<KwfDriver> drivers = driverDao.findDriver(new HashMap(){{ put("phone", params.getPhone()); }});
            if (CollectionUtils.isEmpty(drivers)) {
                /**新增**/
                String salt = PasswordUtils.generateSalt();
                String md5 = PasswordUtils.md5(params.getPhone());
                String password = PasswordUtils.entryptPassword(params.getPhone() + md5, salt);
                params.setSalt(salt);
                params.setPassword(password);
                params.setEntId(LoginUserHolder.getEntId());
                params.setBusinessStatus(Global.NO);
                params.setStatus(Global.NO);
                int count = driverDao.insert(params);

                /**司机信息与企业关联信息**/
                driverEntEdit(params);
                return count > 0 ? HttpResult.ok("司机信息新增成功！", params) : HttpResult.error("司机信息新增失败！");
            } else {
                KwfDriver driver = drivers.get(Global.NUMERICAL_ZERO);
                BeanUtils.copyPropertiesValue(params, driver);
                int count = driverDao.updateById(driver);

                /**司机信息与企业关联信息**/
                KwfDriver driverEnt = new KwfDriver();
                driverEnt.setEntId(LoginUserHolder.getEntId());
                driverEnt.setId(driver.getId());
                driverEntEdit(driverEnt);
                return count > 0 ? HttpResult.ok("司机信息修改成功！", driver) : HttpResult.error("司机信息修改失败！");
            }
        } else {
            /**唯一性交易**/
            List<KwfDriver> drivers = driverDao.findDriver(new HashMap(){{ put("phone", params.getPhone()); }});
            //校验list中对象key值是否存在与value不一致的情况
            boolean bool = listByKeyValue(drivers, params.getId());
            if (bool) {
                return HttpResult.error("司机信息电话号码已存在！");
            }

            /**更新**/
            int count = driverDao.updateById(params);
            return count > 0 ? HttpResult.ok("司机信息修改成功！", params) : HttpResult.error("司机信息修改失败！");
        }
    }

    /**
     * @param params 参数
     * @desc 新增身份证信息
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult driverCardEdit(KwfDriverCardDto params) {
        /**数据校验**/
        if (StringUtils.isBlank(params.getDriverId())) {
            return HttpResult.error(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE,"司机信息ID不能为空！");
        }
        KwfDriver driver = driverDao.selectById(params.getDriverId());
        if (driver == null) {
            return HttpResult.error("司机信息不存在！");
        }

        /**数据copy**/
        KwfDriverCard driverCard = new KwfDriverCard();
        BeanUtils.copyProperties(params, driverCard);
        driverCard.setStatus(Global.YES);
        String certificateMain = driverCard.getCertificateMain();
        String certificateRevolt = driverCard.getCertificateRevolt();
        if (StringUtils.isBlank(certificateMain) && StringUtils.isBlank(certificateRevolt)) {
            driverCard.setStatus(Global.NO);
            driverCard.setCertificateMain(Global.EMPTY_STRING);
            driverCard.setCertificateRevolt(Global.EMPTY_STRING);
        }
        driverCard.setCertificateMain(StringUtils.isBlank(certificateMain)
                ? Global.EMPTY_STRING : driverCard.getCertificateMain());
        driverCard.setCertificateRevolt(StringUtils.isBlank(certificateRevolt)
                ? Global.EMPTY_STRING : driverCard.getCertificateRevolt());

        /**数据更新**/
        int count = 0;
        KwfDriverCard card = KwfDriverCardDao.findByDriverId(params.getDriverId());
        if (card == null) {
            count = KwfDriverCardDao.insert(driverCard);
        } else {
            driverCard.setId(card.getId());
            count = KwfDriverCardDao.updateById(driverCard);
        }

        /**校验司机是否有证书并更新状态**/
        checkLicense(driverCard.getDriverId());
        return count > 0 ? HttpResult.ok("身份证信息修改成功！") : HttpResult.error("身份证信息修改失败！");
    }

    /**
     * @param key 参数
     * @desc 查询身份证信息
     * @author zk
     * @date 2023/7/7
     **/
    public KwfDriverCard findCarByKey(Long key) {
        return KwfDriverCardDao.findByDriverId(key);
    }

    /**
     * @param params 参数
     * @desc 新增司机驾驶证信息
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult driverLicenseEdit(KwfDriverLicenseDto params) {
        /**数据校验**/
        if (StringUtils.isBlank(params.getDriverId())) {
            return HttpResult.error(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE,"司机信息ID不能为空！");
        }
        KwfDriver driver = driverDao.selectById(params.getDriverId());
        if (driver == null) {
            return HttpResult.error("司机信息不存在！");
        }

        /**数据copy**/
        KwfDriverLicense driverLicense = new KwfDriverLicense();
        BeanUtils.copyProperties(params, driverLicense);
        driverLicense.setStatus(Global.YES);
        String certificateMain = driverLicense.getCertificateMain();
        String certificateRevolt = driverLicense.getCertificateRevolt();
        if (StringUtils.isBlank(certificateMain) && StringUtils.isBlank(certificateRevolt)) {
            driverLicense.setStatus(Global.NO);
            driverLicense.setCertificateMain(Global.EMPTY_STRING);
            driverLicense.setCertificateRevolt(Global.EMPTY_STRING);
        }
        driverLicense.setCertificateMain(StringUtils.isBlank(certificateMain)
                ? Global.EMPTY_STRING : driverLicense.getCertificateMain());
        driverLicense.setCertificateRevolt(StringUtils.isBlank(certificateRevolt)
                ? Global.EMPTY_STRING : driverLicense.getCertificateRevolt());

        /**数据更新**/
        int count = 0;
        KwfDriverLicense license = KwfDriverLicenseDao.findByDriverId(params.getDriverId());
        if (license == null) {
            count = KwfDriverLicenseDao.insert(driverLicense);
            return count > 0 ? HttpResult.ok("司机驾驶证信息更新成功！") : HttpResult.error("司机驾驶证信息更新失败！");
        } else {
            driverLicense.setId(license.getId());
            count = KwfDriverLicenseDao.updateById(driverLicense);
        }

        /**校验司机是否有证书并更新状态**/
        checkLicense(driverLicense.getDriverId());
        return count > 0 ? HttpResult.ok("司机驾驶证信息修改成功！") : HttpResult.error("司机驾驶证信息修改失败！");
    }

    /**
     * @param key 参数
     * @desc 查询司机驾驶证信息
     * @author zk
     * @date 2023/7/7
     **/
    public KwfDriverLicense findLicenseByKey(Long key) {
        return KwfDriverLicenseDao.findByDriverId(key);
    }

    /**
     * @param params 参数
     * @desc 新增司机从业资格证
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult driverQualificationEdit(KwfDriverQualificationDto params) {
        /**数据校验**/
        if (StringUtils.isBlank(params.getDriverId())) {
            return HttpResult.error(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE,"司机信息ID不能为空！");
        }
        KwfDriver driver = driverDao.selectById(params.getDriverId());
        if (driver == null) {
            return HttpResult.error("司机信息不存在！");
        }

        /**数据copy**/
        KwfDriverQualification driverQual = new KwfDriverQualification();
        BeanUtils.copyProperties(params, driverQual);
        driverQual.setStatus(Global.YES);
        String certificateMain = driverQual.getCertificateMain();
        String certificateRevolt = driverQual.getCertificateRevolt();
        if (StringUtils.isBlank(certificateMain) && StringUtils.isBlank(certificateRevolt)) {
            driverQual.setStatus(Global.NO);
            driverQual.setCertificateMain(Global.EMPTY_STRING);
            driverQual.setCertificateRevolt(Global.EMPTY_STRING);
        }
        driverQual.setCertificateMain(StringUtils.isBlank(certificateMain) ? Global.EMPTY_STRING : driverQual.getCertificateMain());
        driverQual.setCertificateRevolt(StringUtils.isBlank(certificateRevolt) ? Global.EMPTY_STRING : driverQual.getCertificateRevolt());

        /**数据更新**/
        int count = 0;
        KwfDriverQualification qualification = KwfDriverQualificationDao.findByDriverId(params.getDriverId());
        if (qualification == null) {
            count = KwfDriverQualificationDao.insert(driverQual);
        } else {
            driverQual.setId(qualification.getId());
            count = KwfDriverQualificationDao.updateById(driverQual);
        }

        /**校验司机是否有证书并更新状态**/
        checkLicense(driverQual.getDriverId());
        return count > 0 ? HttpResult.ok("司机从业资格证信息修改成功！") : HttpResult.error("司机从业资格证信息修改失败！");
    }

    /**
     * @param key 参数
     * @desc 查询司机从业资格证
     * @author zk
     * @date 2023/7/7
     **/
    public KwfDriverQualification findQualificationByKey(Long key) {
        return KwfDriverQualificationDao.findByDriverId(key);
    }

    /**
     * @param params 参数
     * @desc 新增司机信息与企业关联信息
     * @author zk
     * @date 2023/7/7
     **/
    public int driverEntEdit(KwfDriver params) {
        KwfDriverEnt driverEnt = new KwfDriverEnt();
        driverEnt.setDriverId(params.getId());
        driverEnt.setEntId(params.getEntId() == null ? LoginUserHolder.getEntId() : params.getEntId());
        KwfDriverEnt ent = driverEntDao.findByDriverEnt(driverEnt);
        if (ent == null) {
            int count = driverEntDao.insert(driverEnt);
            return count;
        }
        return Global.MINUS_ONE;
    }

    /**
     * @param driverId 司机档案主键id fleetId 车队班组主键id
     * @desc 车队班组绑定
     * @author zk
     * @date 2023/7/7
     **/
    public HttpResult driverFleetEdit(Long driverId, Long fleetId) {
        /**数据校验**/
        if (fleetId == null) {
            return HttpResult.ok("未选择车队班组！");
        }
        KwfFleetDriver queryFleetDriver = new KwfFleetDriver();
        queryFleetDriver.setEntId(LoginUserHolder.getEntId());
        queryFleetDriver.setDriverId(driverId);
        KwfFleetDriver fleetDriver = fleetDriverDao.findByTruckDriver(queryFleetDriver);

        /**数据更新**/
        queryFleetDriver.setFleetId(fleetId);
        if (fleetDriver == null) {
            int count = fleetDriverDao.insert(queryFleetDriver);
            return count > 0 ? HttpResult.ok("车队班组绑定成功！") : HttpResult.error("车队班组绑定失败！");
        } else {
            queryFleetDriver.setId(fleetDriver.getId());
            int count = fleetDriverDao.updateById(queryFleetDriver);
            return count > 0 ? HttpResult.ok("车队班组绑定成功！") : HttpResult.error("车队班组绑定失败！");
        }
    }

    /**
     * @param driverId 司机id
     * @param entId 企业id
     * @desc 查询车队班组
     * @author zk
     * @date 2023/7/20
     **/
    public KwfFleet findByFleetDriver(Long driverId, Long entId) {
        return fleetDriverDao.findByFleetDriver(driverId, entId);
    }

    /**
     * @param params 参数
     * @desc: 修改密码
     * @author: zk
     * @date: 2023/7/11
     */
    public HttpResult updatePassword(UpdatePasswordDto params) {
        /**获取信息**/
        Long driverId = LoginUserHolder.getUserId();
        driverId = driverId == null ? params.getDriverId() : driverId;
        KwfDriver driver = driverDao.selectById(driverId);
        if (driver == null) {
            return HttpResult.error("信息不存在！");
        }

        /**校验**/
        String key = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY,
                DictEnum.SMS_UPDATE_PASSWORD.getValue(),
                params.getAccount());
        RedissonUtils.putString(key, params.getCaptcha(), RedisConstant.SMS_VERIFY_CODE_VALID_TIME);
        String smsCaptcha = RedissonUtils.getString(key);
        if (StringUtils.isBlank(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码不能为空！");
        }
        if (StringUtils.isBlank(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码已过期,请重新获取！");
        }
        if (!params.getCaptcha().equals(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码不正确，请确认再输入！");
        }

        /**更新数据**/
        String salt = PasswordUtils.generateSalt();
        String password = PasswordUtils.entryptPassword(driver.getPhone() + params.getPassword(), salt);
        driver.setPassword(password);
        driver.setSalt(salt);
        int count = driverDao.updateById(driver);
        return count > 0 ? HttpResult.ok("密码修改成功！") : HttpResult.error("密码修改失败！");
    }

    /**
     * @param {driverId 司机主键id/登陆后缓存中取、phone 手机号、captcha 短信验证码}
     * @description 更换手机号
     * @author zk
     * @date 2023/07/11
     **/
    public HttpResult replacePhone(ReplacePhoneDto params) {
        /**获取信息**/
        Long driverId = params.getDriverId();
        driverId = driverId == null ? LoginUserHolder.getUserId() : driverId;
        KwfDriver driver = driverDao.selectById(driverId);
        if (driver == null) {
            return HttpResult.error("信息不存在！");
        }

        /**从缓存中取出验证码/校验**/
        String key = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY, DictEnum.SMS_UPDATE_PASSWORD.getValue(), params.getPhone());
        String smsCaptcha = RedissonUtils.getString(key);
        if (StringUtils.isBlank(smsCaptcha)) {
            return HttpResult.error("验证码已过期,请重新获取！！");
        }
        if (!smsCaptcha.equals(params.getCaptcha())) {
            return HttpResult.error("验证码不正确，请确认再输入！");
        }

        /**唯一性交易**/
        List<KwfDriver> drivers = driverDao.findDriver(new HashMap(){{ put("phone", params.getPhone()); }});
        if (!CollectionUtils.isEmpty(drivers)) {
            return HttpResult.error("电话号码已存在！");
        }

        /**更新数据**/
        String salt = PasswordUtils.generateSalt();
        String password = PasswordUtils.entryptPassword(params.getPhone() + PasswordUtils.md5(params.getPhone()), salt);
        driver.setPassword(password);
        driver.setSalt(salt);
        driver.setPhone(params.getPhone());
        int count = driverDao.updateById(driver);
        return count > 0 ? HttpResult.ok("手机号更换成功！") : HttpResult.error("手机号更换失败！");
    }

    /**
     * @param {account 账号、password 密码、captcha 验证码}
     * @description 忘记密码
     * @author zk
     * @date 2023/08/15
     **/
    public HttpResult forgetPassword(ForgetPasswordDto params) {
        /**校验**/
        String key = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY, DictEnum.SMS_UPDATE_PASSWORD.getValue(), params.getAccount());
        RedissonUtils.putString(key, params.getCaptcha(), RedisConstant.SMS_VERIFY_CODE_VALID_TIME);
        String smsCaptcha = RedissonUtils.getString(key);
        if (StringUtils.isBlank(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码不能为空！");
        }
        if (StringUtils.isBlank(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码已过期,请重新获取！");
        }
        if (!params.getCaptcha().equals(smsCaptcha)){
            return HttpResult.error(HttpStatus.UN_LOGIN_CODE, "验证码不正确，请确认再输入！");
        }

        /**查询**/
        List<KwfDriver> drivers = driverDao.findDriver(new HashMap(){{ put("phone", params.getAccount()); }});
        if (CollectionUtils.isEmpty(drivers)) {
            return HttpResult.error("账号不存在，请确认后再输入！");
        }
        KwfDriver driver = drivers.get(Global.NUMERICAL_ZERO);

        /**更新数据**/
        String salt = PasswordUtils.generateSalt();
        String password = PasswordUtils.entryptPassword(driver.getPhone() + params.getPassword(), salt);
        driver.setPassword(password);
        driver.setSalt(salt);
        int count = driverDao.updateById(driver);
        return count > 0 ? HttpResult.ok("密码修改成功！") : HttpResult.error("密码修改失败！");
    }

    /**
     * @param file 上传文件
     * @desc 上传文件持久化
     * @author zk
     * @date 2023/7/6
     **/
    public void importFileSave(MultipartFile file) {
        FileInfo fileInfo = FileUtils.getFileDataList(file);
        fileInfo.setType(FileEnum.FILE_STORE_TYPE_OSS.getFileType());
        FileInfo returnFileInfo = FileUtils.uploadFileInfo(file, fileInfo, FileEnum.FILE_STORE_TYPE_OSS);

        KwfDriverImport driverImport = new KwfDriverImport();
        driverImport.setEntId(LoginUserHolder.getEntId());
        driverImport.setUrl(returnFileInfo.getFilePath());
        driverImport.setRemark(JSON.toJSONString(returnFileInfo));
        kwfDriverImportDao.insert(driverImport);

//        try {
//            //remoteFileService.fileInfoInsert(fileInfo);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    /**
     * @desc 企业司机统计
     * @author zk
     * @date 2023/9/18
     **/
    public Map<String, Object> driverStatistics() {
        return driverDao.driverStatistics(LoginUserHolder.getEntId());
    }

    /**
     * @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 params 参数
     * @desc 校验司机是否有证书
     * @author zk
     * @date 2023/7/11
     **/
    public boolean checkLicense(KwfDriverDto params) {
        //身份证
        KwfDriverCardDto card = params.getDriverCard();
        if (card == null || (StringUtils.isBlank(card.getCertificateMain()) && StringUtils.isBlank(card.getCertificateRevolt()))) {
            return false;
        }
        //司机驾驶证信息
        KwfDriverLicenseDto license = params.getDriverLicense();
        if (license == null || (StringUtils.isBlank(license.getCertificateMain()) && StringUtils.isBlank(license.getCertificateRevolt()))) {
            return false;
        }
        //司机从业资格证
        KwfDriverQualificationDto quali = params.getDriverQualification();
        if (quali == null || (StringUtils.isBlank(quali.getCertificateMain()) && StringUtils.isBlank(quali.getCertificateRevolt()))) {
            return false;
        }
        return true;
    }

    /**
     * @param file 上传文件
     * @desc 参数校验
     * @author zk
     * @date 2023/8/16
     **/
    public HttpResult checkParams(MultipartFile file) {
        ExcelReader excelReader = null;
        try {
            /**数据校验**/
            if (ExcelUtil.checkExcel(file)) {
                return HttpResult.error("请上传Excel格式的文件！");
            }

            ExcelImportListener importListener = new ExcelImportListener();
            InputStream inputStream = file.getInputStream();
            excelReader = EasyExcel.read(inputStream, importListener).build();

            ReadSheet readSheet = EasyExcel.readSheet( 0) .headRowNumber(2).head(KwfDriverExcelImportDto .class).build();
            excelReader.read(readSheet);
            if (importListener.getErrorList().size() > 0) {
                return HttpResult.error(HttpStatus.GLOBAL_EXCEPTION_CODE, "数据格式不正确，请确认！", importListener.getErrorList());
            }
            if (importListener.getDataList().size() == 0) {
                return HttpResult.error("导入数据不能空！");
            }

            return HttpResult.ok(importListener.getDataList());
        } catch (Exception e) {
            e.printStackTrace();
            return HttpResult.error("司机导入异常！");
        } finally {
            if (excelReader != null) {
                excelReader.finish();
            }
        }
    }

    /**
     * @param driverId 司机id
     * @desc 校验司机是否有证书并更新状态
     * @author zk
     * @date 2023/7/11
     **/
    public void checkLicense(Long driverId) {
        //身份证
        KwfDriverCard card = this.findCarByKey(driverId);
        if (card == null || (StringUtils.isBlank(card.getCertificateMain()) && StringUtils.isBlank(card.getCertificateRevolt()))) {
            return;
        }
        //司机驾驶证信息
        KwfDriverLicense license = this.findLicenseByKey(driverId);
        if (license == null || (StringUtils.isBlank(license.getCertificateMain()) && StringUtils.isBlank(license.getCertificateRevolt()))) {
            return;
        }
        //司机从业资格证
        KwfDriverQualification quali = this.findQualificationByKey(driverId);
        if (quali == null || (StringUtils.isBlank(quali.getCertificateMain()) && StringUtils.isBlank(quali.getCertificateRevolt()))) {
            return;
        }
        //更新数据
        KwfDriver driver = new KwfDriver();
        driver.setId(driverId);
        driver.setAuthStatus(Global.NUMERICAL_ONE);
        driverDao.updateById(driver);
    }
    /**
     * 校验list中对象key值是否存在与value不一致的情况
     * @param list 数据集
     * @param value 匹配值
     * @return
     */
    public static boolean listByKeyValue(List<KwfDriver> list, Long value) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        for (KwfDriver driver:list) {
            if (value != null && !driver.getId().equals(value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param params 参数
     * @desc 绑定车辆
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult bindTruck(KwfBindTruckDto params) {
         bindTruck(params.getId(), params.getTruckId(),null);
         return HttpResult.ok();
    }

    /**
     * @param params 参数
     * @desc 绑定车辆
     * @author zk
     * @date 2023/7/6
     **/
    public void bindTruck(Long driverId, Long truckId,Long entId) {
        log.info("绑定车辆，入参参数，driverId：{}， truckId：{}", driverId, truckId);
        if (driverId == null || truckId == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "司机id和车辆id不能为空!");
        }
        if (Objects.nonNull(LoginUserHolder.getEntId())) {
            entId = LoginUserHolder.getEntId();
         }
        //查询司机是否存在已绑定的车辆
        KwfTruckReport truckReport = truckReportRepository.getOne(Wrappers.<KwfTruckReport>lambdaQuery()
                .eq(KwfTruckReport::getEntId, entId)
                .eq(KwfTruckReport::getDriverId, driverId)
                .eq(KwfTruckReport::getDelFlag, Global.NO)
                .eq(KwfTruckReport::getStatus, Global.YES));
        if(truckReport == null) {
            KwfTruckReport newTruckReport = new KwfTruckReport();
            newTruckReport.setTruckId(truckId);
            newTruckReport.setDriverId(driverId);
            newTruckReport.setEntId(entId);
            newTruckReport.setStatus(Global.YES);
            boolean saveResult = truckReportRepository.save(newTruckReport);
            if (!saveResult) {
                throw new BusinessPlatfromException(ErrorCodeEnum.DB_OPERATE_FAIL, "车辆绑定失败!");
            }
        } else {
            if (truckReport.getTruckId().equals(truckId)) {
                throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_EXIST, "此车辆已与此司机绑定，请重选选择车辆!");
            }
            truckReport.setTruckId(truckId);
            boolean updateResult = truckReportRepository.updateById(truckReport);
            if (!updateResult) {
                throw new BusinessPlatfromException(ErrorCodeEnum.DB_OPERATE_FAIL, "车辆绑定失败!");
            }
        }
        log.info("接绑定车辆成功！");
    }


    /**
     * 查询司机关联车辆信息
     * @param request
     * @return
     */
    public List<KwfDriverAssociatedTrackVO> queryAssociatedTrack(AssociatedTrackRequest request) {
        log.info("查询司机关联车辆信息：{}", JSON.toJSONString(request));
        List<KwfDriverAssociatedTruck> associatedTrackList = driverAssociatedTruckRepository
                .queryByEntIdAndDriverId(request.getEntId(),request.getDriverId());
        if (CollectionUtils.isEmpty(associatedTrackList)) {
            return Collections.emptyList();
        }
        List<KwfDriverAssociatedTrackVO> associatedTrackVOList = associatedTrackList.stream().map(truck ->{
            KwfDriverAssociatedTrackVO vo = new KwfDriverAssociatedTrackVO();
            TmsTruckAxleNum carAxisInfo = getCarAxisInfo(truck.getTruckAxleId());
            vo.setId(truck.getId());
            vo.setTruckNo(truck.getTruckNo());
            vo.setTruckAxleName(carAxisInfo.getName());
            vo.setLegalLoad(carAxisInfo.getLegalLoad());
            vo.setStatus(truck.getStatus());
            return vo;
        }).collect(Collectors.toList());
        log.info("查询司机关联车辆信息完成，结果：{}", JSON.toJSONString(associatedTrackVOList));
        return associatedTrackVOList;
    }


    /**
     * 根据车轴id查询轴数信息
     *
     * @param truck
     * @param ents
     * @return
     */
    private TmsTruckAxleNum getCarAxisInfo(Long axleNumId) {
        if (axleNumId == null) {
            return new TmsTruckAxleNum();
        }
        //查询车辆关联司机信息
        TmsTruckAxleNum axleNum = truckAxleNumRepository.getOne(Wrappers.<TmsTruckAxleNum>lambdaQuery()
                .eq(TmsTruckAxleNum::getStatus, 1)
                .eq(TmsTruckAxleNum::getId, axleNumId));
        if (axleNum == null) {
            return new TmsTruckAxleNum();
        }
        return axleNum;
    }

    /**
     * 新增车辆关系
     * @param request
     * @return
     */
    public void addAssociatedTrack(AssociatedTrackAddRequest request) {
        log.info("新增司机关联车辆信息：{}", JSON.toJSONString(request));
        //校验
        List<KwfDriverAssociatedTruck> associatedTrackList = checkKwfDriverAssociatedTracks(request);

        //设置关联状态（首次关联设为当前车辆，并将原有当前车辆置为非当前）
        KwfDriverAssociatedTruck associatedTrack = new KwfDriverAssociatedTruck();
        associatedTrack.setEntId(request.getEntId());
        associatedTrack.setDriverId(request.getDriverId());
        associatedTrack.setTruckNo(request.getTruckNo());
        associatedTrack.setTruckAxleId(request.getTruckAxleId());
        associatedTrack.setCreateUser(request.getDriverId());
        //首次关联默认设为当前车辆；
        associatedTrack.setStatus(associatedTrackList.isEmpty() ? Global.YES : Global.NO);
        driverAssociatedTruckRepository.save(associatedTrack);
        log.info("新增司机关联车辆成功，记录ID：{}，车牌：{}", associatedTrack.getId(), request.getTruckNo());
    }

    /**
     * 新增车辆校验
     * @param request
     * @return
     */
    private List<KwfDriverAssociatedTruck> checkKwfDriverAssociatedTracks(AssociatedTrackAddRequest request) {
        int systemType = LoginUserHolder.getSystemType();
        if (systemType == SystemTypeEnum.DRIVER.getCode()) {
            //查询企业下的车辆信息
            List<KwfTruck> kwfTrucks = truckService.findTruckByEntIds(request.getEntId());
            if (CollectionUtils.isEmpty(kwfTrucks)) {
                throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_NOT_FOUND, "您所在的企业暂无该车辆，请与企业管理人员联系");
            }
            //校验输入的车牌和轴数
            KwfTruck matchedTruck = kwfTrucks.stream()
                    .filter(truck ->
                            Objects.equals(request.getTruckNo(), truck.getTruckNo()) &&
                                    Objects.equals(String.valueOf(request.getTruckAxleId()), truck.getCarAxis()))
                    .findFirst().orElse(null);
            if (matchedTruck == null) {
                throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_NOT_FOUND, "您所在的企业暂无该车辆，请与企业管理人员联系");
            }
        }
        //校验车辆是否已存在
        List<KwfDriverAssociatedTruck> associatedTrackList = driverAssociatedTruckRepository.queryByEntIdAndDriverId(request.getEntId(), request.getDriverId());
        boolean isDuplicate = associatedTrackList.stream()
                .anyMatch(track -> Objects.equals(track.getTruckNo(), request.getTruckNo()));
        if (isDuplicate) {
            throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_EXIST, "司机已关联车牌[" + request.getTruckNo() + "]，无需重复添加");
        }

        //校验新增车辆是否有未完成运单
        CapacityTruckParam param = new CapacityTruckParam();
        param.setTruckNo(request.getTruckNo());
        param.setEntId(request.getEntId());
        List<RWaybillOrderVo> waybillVos = transportRemoteService.queryWaybillOrder(param);
        if (CollectionUtils.isNotEmpty(waybillVos)) {
            //首次关联不能新增
            if (CollectionUtils.isEmpty(associatedTrackList)) {
                throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_EXIST, "当前车辆正在任务中，请稍后进行添加");
            }
            // 非首次关联，允许添加但不设为当前车辆
            log.info("非首次关联，允许添加有未完成运单的车辆[{}]", request.getTruckNo());
        }
        return associatedTrackList;
    }

    /**
     * 删除司机关联车辆
     * @param id
     */
    public void deleteAssociatedTrack(Long id) {
        log.info("删除司机关联车辆：{}", id);
        //校验
        if (id == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "id不能为空！");
        }
        KwfDriverAssociatedTruck associatedTrack = driverAssociatedTruckRepository.getById(id);
        if (associatedTrack == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_NOT_FOUND, "司机关联车辆信息不存在!");
        }
        //校验车辆是否有未完成运单
        checkTruckHasUnfinishedWaybill(associatedTrack.getTruckNo(), associatedTrack.getEntId() , false);
        associatedTrack.setDelFlag(Global.YES);
        if (!driverAssociatedTruckRepository.updateById(associatedTrack)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DATA_DELETE_FAIL, "删除失败");
        }

        log.info("删除司机关联车辆成功!");
    }

    /**
     * 切换关联车辆
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public void switchAssociatedTrack(Long id) {
        log.info("切换关联车辆id：{}", id);
        //校验
        if (id == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "id不能为空！");
        }
        KwfDriverAssociatedTruck newTrack = driverAssociatedTruckRepository.getById(id);
        if (newTrack == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_NOT_FOUND, "司机关联车辆信息不存在!");
        }
        if (newTrack.getStatus() == Global.YES) {
            throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_STATUS_ERROR, "所选车辆为当前车辆，不能切换，请重新选择！");
        }
        //校验新车辆是否有未完成运单
        checkTruckHasUnfinishedWaybill(newTrack.getTruckNo(), newTrack.getEntId() , true);

        //先更改旧关联车辆
        LambdaQueryWrapper<KwfDriverAssociatedTruck> queryWrapper = Wrappers.<KwfDriverAssociatedTruck>lambdaQuery()
                .eq(KwfDriverAssociatedTruck::getDriverId, newTrack.getDriverId())
                .eq(KwfDriverAssociatedTruck::getEntId, newTrack.getEntId())
                .eq(KwfDriverAssociatedTruck::getStatus, Global.YES);
        KwfDriverAssociatedTruck oldTrack = driverAssociatedTruckRepository.getOne(queryWrapper);
        if (oldTrack != null) {
            //校验旧车辆否有未完成运单
            checkTruckHasUnfinishedWaybill(oldTrack.getTruckNo(), oldTrack.getEntId() , false);
            oldTrack.setStatus(Global.NO);
            driverAssociatedTruckRepository.updateById(oldTrack);
            log.info("旧关联车辆[{}]已取消", oldTrack.getTruckNo());
        }
        //更改新关联车辆
        newTrack.setStatus(Global.YES);
        driverAssociatedTruckRepository.updateById(newTrack);
        log.info("关联车辆切换成功，新车辆[{}]",newTrack.getTruckNo());
    }


    /**
     * 校验车辆是否有未完成运单
     */
    private void checkTruckHasUnfinishedWaybill(String truckNo, Long entId, boolean isNew) {
        if (truckNo == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, isNew ? "新关联车辆号为空！" : "旧关联车辆号为空！");
        }
        CapacityTruckParam param = new CapacityTruckParam();
        param.setTruckNo(truckNo);
        param.setEntId(entId);
        List<RWaybillOrderVo> waybillVos = transportRemoteService.queryWaybillOrder(param);
        if (CollectionUtils.isNotEmpty(waybillVos)) {
            String msg = isNew ?
                    String.format("新关联车辆[%s]有未完成运单，无法切换！", truckNo) :
                    String.format("当前车辆[%s]有未完成运单，无法切换！", truckNo);
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_UNFINISHED, msg);
        }
    }


    /**
     * @param params 参数
     * @desc 解绑车辆
     * @author zk
     * @date 2023/7/6
     **/
    public HttpResult unbindTruck(KwfBindTruckDto params) {
        //查询司机是否存在已绑定的车辆
        KwfTruckReport truckReport = truckReportRepository.getOne(Wrappers.<KwfTruckReport>lambdaQuery()
                .eq(KwfTruckReport::getEntId, LoginUserHolder.getEntId())
                .eq(KwfTruckReport::getDriverId, params.getId())
                .eq(KwfTruckReport::getDelFlag, Global.NO)
                .eq(KwfTruckReport::getStatus, Global.YES));
        if(truckReport == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "此司机无车辆解绑信息！");
        }
        truckReport.setStatus(Global.NO);
        boolean saveResult = truckReportRepository.updateById(truckReport);
        return saveResult ? HttpResult.ok("车辆解绑成功！") : HttpResult.error("车辆解绑失败！");

    }

    /**
     * @param params 参数
     * @desc 保存车库
     * @author zk
     * @date 2023/7/6
     **/
    public void saveAssociatedTruck(SaveAssociatedTruckParam param) {
        log.info("新增司机关联车辆信息：{}", JSON.toJSONString(param));
        Long entId = LoginUserHolder.getEntId();
        List<String> truckNos = param.getAssociatedTruckVO().stream().map(item -> item.getTruckNo()) .distinct().collect(Collectors.toList());
        //校验车辆是否已存在
        List<KwfDriverAssociatedTruck> associatedTrackList = driverAssociatedTruckRepository.queryByEntIdAndDriverId(entId, param.getDriverId());
        //已经关联的车牌
        Set<String> existingTruckNos = associatedTrackList.stream()
                .map(KwfDriverAssociatedTruck::getTruckNo)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 获取所有重复的车辆号
        List<String> duplicateTruckNos = truckNos.stream()
                .filter(existingTruckNos::contains)
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(duplicateTruckNos)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.ASSOCIATED_TRUCK_EXIST, "司机已关联车牌[" + JSON.toJSONString(duplicateTruckNos) + "]，无需重复添加");
        }

        for (SaveAssociatedTruckParam.AssociatedTruckVO vo : param.getAssociatedTruckVO()) {
            //设置关联状态（首次关联设为当前车辆，并将原有当前车辆置为非当前）
            KwfDriverAssociatedTruck associatedTrack = new KwfDriverAssociatedTruck();
            associatedTrack.setEntId(entId);
            associatedTrack.setDriverId(param.getDriverId());
            associatedTrack.setTruckNo(vo.getTruckNo());
            associatedTrack.setTruckAxleId(vo.getTruckAxleId());
            associatedTrack.setCreateUser(param.getDriverId());
            //首次关联默认设为当前车辆；
            associatedTrack.setStatus(associatedTrackList.isEmpty() ? Global.YES : Global.NO);
            driverAssociatedTruckRepository.save(associatedTrack);
        }
        log.info("新增司机关联车辆成功!");
    }


    /**
     * @param
     * @desc 查询
     * @author zk
     * @date 2023/7/6
     **/
    public Integer countDriversByEntId(Long entId) {
        return driverMapper.countDriversByEntId(entId);
    }

}
