package com.ningdatech.carapi.driver.manage;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import com.ningdatech.carapi.car.position.model.po.ReqDataPO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.*;
import com.ningdatech.carapi.common.aop.BuildChildrenRegionWrapper;
import com.ningdatech.carapi.common.constant.*;
import com.ningdatech.carapi.common.contants.DefValConstants;
import com.ningdatech.carapi.common.helper.UserInfoHelper;
import com.ningdatech.carapi.common.model.FileBasicInfo;
import com.ningdatech.carapi.common.util.CodeUtil;
import com.ningdatech.carapi.common.util.ExcelDownUtil;
import com.ningdatech.carapi.common.util.ExcelExportStyle;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.contants.LambdaDataScopeTypeEnum;
import com.ningdatech.carapi.driver.constant.*;
import com.ningdatech.carapi.driver.constants.DriverConstant;
import com.ningdatech.carapi.driver.entity.*;
import com.ningdatech.carapi.driver.helper.RegistrationAvailableCheckHelper;
import com.ningdatech.carapi.driver.model.DriverArchivesExportDTO;
import com.ningdatech.carapi.driver.model.dto.DriverBasicInfoDTO;
import com.ningdatech.carapi.driver.model.po.*;
import com.ningdatech.carapi.driver.model.vo.ResArchivalInfoDetailVO;
import com.ningdatech.carapi.driver.model.vo.ResArchivalInfoSearchListVO;
import com.ningdatech.carapi.driver.model.vo.ResDriverTrainingRegistrationListVO;
import com.ningdatech.carapi.driver.service.*;
import com.ningdatech.carapi.qrcode.entity.NdVehicleGetOn;
import com.ningdatech.carapi.qrcode.service.VehicleGetOnService;
import com.ningdatech.carapi.safe.entity.NdVehicleViolation;
import com.ningdatech.carapi.safe.manage.VehicleAccidentManage;
import com.ningdatech.carapi.safe.model.dto.AccidentPageQuery;
import com.ningdatech.carapi.safe.model.vo.NdVehicleAccidentAnalysisVO;
import com.ningdatech.carapi.safe.model.vo.NdVehicleAccidentDeadVO;
import com.ningdatech.carapi.safe.model.vo.NdVehicleAccidentVO;
import com.ningdatech.carapi.safe.model.vo.NdVehicleViolationVO;
import com.ningdatech.carapi.safe.service.INdVehicleAccidentAnalysisService;
import com.ningdatech.carapi.safe.service.INdVehicleAccidentDeadService;
import com.ningdatech.carapi.safe.service.INdVehicleAccidentService;
import com.ningdatech.carapi.safe.service.INdVehicleViolationService;
import com.ningdatech.carapi.sys.contants.UserLoginConstant;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.entity.MetaApply;
import com.ningdatech.carapi.sys.entity.UserRole;
import com.ningdatech.carapi.sys.entity.constant.ImportTemplateConstant;
import com.ningdatech.carapi.sys.entity.dto.CompanyDTO;
import com.ningdatech.carapi.sys.entity.enumeration.BooleanDisplayEnum;
import com.ningdatech.carapi.sys.entity.enumeration.ImportTemplateEnum;
import com.ningdatech.carapi.sys.entity.enumeration.MetaApplyStatusEnum;
import com.ningdatech.carapi.sys.entity.enumeration.MetaApplyTypeEnum;
import com.ningdatech.carapi.sys.helper.CompaniesCacheHelper;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;
import com.ningdatech.carapi.sys.service.IMetaApplyService;
import com.ningdatech.carapi.sys.service.UserRoleService;
import com.ningdatech.carapi.user.entity.NdUserAuth;
import com.ningdatech.carapi.user.entity.NdUserInfo;
import com.ningdatech.carapi.user.model.vo.UserBasicInfoVO;
import com.ningdatech.carapi.user.security.auth.constant.AuthTypeEnum;
import com.ningdatech.carapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.carapi.user.service.INdUserAuthService;
import com.ningdatech.carapi.user.service.INdUserInfoService;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author liuxinxin
 * @date 2022/10/9 上午10:33
 */

@Component
@RequiredArgsConstructor
@Slf4j
public class DriverArchivesManage {

    private final IDriverInfoService iDriverInfoService;
    private final CompanyService companyService;
    private final IMetaApplyService iMetaApplyService;
    private final RegionsCacheHelper regionsCacheHelper;
    private final INdUserInfoService iNdUserInfoService;
    private final INdUserAuthService iNdUserAuthService;
    private final UserRoleService userRoleService;
    private final PasswordEncoder passwordEncoder;
    private final ITrainingRegistrationReviewService iTrainingRegistrationReviewService;
    private final UserInfoHelper userInfoHelper;
    private final INdVehicleAccidentService vehicleAccidentService;
    private final INdVehicleAccidentDeadService vehicleAccidentDeadService;
    private final INdVehicleAccidentAnalysisService vehicleAccidentAnalysisService;
    private final INdVehicleViolationService vehicleViolationService;
    private final CompaniesCacheHelper companiesCacheHelper;
    private final RegistrationAvailableCheckHelper registrationAvailableCheckHelper;
    private final Logger LOG = LoggerFactory.getLogger(DriverArchivesManage.class);
    private final IDriverWorkRecordService iDriverWorkRecordService;
    private final ICertificateService certificateService;
    private final IDriverScoreInfoService iDriverScoreInfoService;
    private final VehicleAccidentManage vehicleAccidentManage;
    private final VehicleGetOnService vehicleGetOnService;
    private final IDriverInfoService driverInfoService;

    public PageVo<ResArchivalInfoSearchListVO> archivalInfoSearch(ReqArchivalInfoSearchPO request) {

        // 按照登录用户，如果是驾驶员登录，只展示该驾驶员信息
        UserInfoDetails userDetail = LoginUserUtil.loginUserDetail();
        Long roleId = userDetail.getRoleId();

        Page<DriverInfo> page = request.page();
        LambdaQueryWrapper<DriverInfo> wrapper = Wrappers.lambdaQuery(DriverInfo.class);
        DriverStatusEnum driverStatus = request.getDriverStatus();
        // 不是离职列表，要加数据权限
        if (Objects.nonNull(driverStatus) && DriverStatusEnum.quit.name().equals(driverStatus.name())) {
            buildQuitInfoSearchQuery(wrapper,request);
        }else {
            // 不是离职列表，要加数据权限
            DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
            context.buildArchivalInfoSearchQuery(wrapper, request);
        }
        if (UserRoleTypeEnum.DRIVER_ROLE_ID.getId().equals(roleId)) {
            Long userId = userDetail.getUserId();
            DriverInfo driverInfo = driverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class).eq(DriverInfo::getUserId, userId));
            if (Objects.nonNull(driverInfo)) {
                Long driverId = driverInfo.getId();
                wrapper.eq(DriverInfo::getId, driverId);
            }
        }

        iDriverInfoService.page(page, wrapper);
        // 培训审核列表查询
        if (0L == page.getTotal()) {
            return PageVo.empty();
        }
        List<DriverInfo> records = page.getRecords();
        List<ResArchivalInfoSearchListVO> returnVoList = records.stream().map(r -> {
            ResArchivalInfoSearchListVO resVo = new ResArchivalInfoSearchListVO();
            BeanUtils.copyProperties(r, resVo);
            resVo.setDriverId(r.getId());
            resVo.setInductionTime(r.getInitialLicenseTime());
            CodeUtil.searchCompanyNameAndRegionName(resVo);
            // 对手机号和身份证号进行脱敏处理
            String phoneNo = r.getPhoneNo();
            String idCard = r.getIdCard();
            String encryptPhone = DesensitizedUtil.mobilePhone(phoneNo);
            String encryptIdCard = DesensitizedUtil.idCardNum(idCard, DriverConstant.ID_CARD_DESENSITIZED_FRONT, DriverConstant.ID_CARD_DESENSITIZED_END);
            resVo.setPhoneNo(encryptPhone);
            resVo.setIdCard(encryptIdCard);
            return resVo;
        }).collect(Collectors.toList());
        return PageVo.of(returnVoList, page.getTotal());
    }

    public PageVo<ResArchivalInfoSearchListVO> archivalInfoSearchOpen(ReqArchivalInfoSearchPO request) {
        Page<DriverInfo> page = request.page();
        LambdaQueryWrapper<DriverInfo> wrapper = Wrappers.lambdaQuery(DriverInfo.class);
        buildArchivalInfoSearchQuery(wrapper, request);
        iDriverInfoService.page(page, wrapper);
        // 培训审核列表查询
        if (0L == page.getTotal()) {
            return PageVo.empty();
        }
        List<DriverInfo> records = page.getRecords();
        List<ResArchivalInfoSearchListVO> returnVoList = records.stream().map(r -> {
            ResArchivalInfoSearchListVO resVo = BeanUtil.copyProperties(r, ResArchivalInfoSearchListVO.class);
            resVo.setDriverId(r.getId());
            resVo.setInductionTime(r.getInitialLicenseTime());
            CodeUtil.searchCompanyNameAndRegionName(resVo);
            return resVo;
        }).collect(Collectors.toList());
        return PageVo.of(returnVoList, page.getTotal());
    }

    public List<ResArchivalInfoSearchListVO> archivalInfoSearchBatchOpen(ReqDataPO po) {
        List<String> idCards = po.getIdCards();
        if(CollUtil.isEmpty(idCards)){
            return Collections.emptyList();
        }
        LambdaQueryWrapper<DriverInfo> wrapper = Wrappers.lambdaQuery(DriverInfo.class);
        buildArchivalInfoSearchQuery(wrapper, idCards);
        List<DriverInfo> list = iDriverInfoService.list(wrapper);
        // 培训审核列表查询
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        return list.stream().map(r -> {
            ResArchivalInfoSearchListVO resVo = BeanUtil.copyProperties(r, ResArchivalInfoSearchListVO.class);
            resVo.setDriverId(r.getId());
            resVo.setInductionTime(r.getInitialLicenseTime());
            CodeUtil.searchCompanyNameAndRegionName(resVo);
            return resVo;
        }).collect(Collectors.toList());
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildArchivalInfoSearchQuery(LambdaQueryWrapper<DriverInfo> wrapper, ReqArchivalInfoSearchPO request) {
        // 获取入参
        String companyName = request.getCompanyName();
        String driverName = request.getDriverName();
        String idCard = request.getIdCard();
        DriverStatusEnum driverStatus = request.getDriverStatus();
        Long companyId = request.getCompanyId();

        // 查询
        String driverStatusStr = Objects.nonNull(driverStatus) ? driverStatus.name() : null;
        wrapper.like(StringUtils.isNotBlank(companyName), DriverInfo::getCompanyName, companyName)
                .like(StringUtils.isNotBlank(driverName), DriverInfo::getDriverName, driverName)
                .ge(request.getStartTime() != null, DriverInfo::getCreateOn, request.getStartTime())
                .le(request.getEndTime() != null, DriverInfo::getCreateOn, request.getEndTime())
                .eq(StringUtils.isNotBlank(idCard), DriverInfo::getIdCard, idCard)
                .eq(StringUtils.isNotBlank(driverStatusStr), DriverInfo::getDriverStatus, driverStatus)
                .eq(Objects.nonNull(companyId), DriverInfo::getCompanyId, companyId)
                .orderByDesc(DriverInfo::getCreateOn)
                .isNotNull(DriverInfo::getCompanyId);
        if (StrUtil.isNotBlank(request.getTrainingRegistrationType())) {
            if (request.getTrainingRegistrationType().equals(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name())) {
                wrapper.eq(DriverInfo::getDriverRegistrationStatus, DriverRegistrationStatusEnum.exam_training_stage.name());
                wrapper.eq(DriverInfo::getDriverRegistrationFlag, TrainingRegistrationFlagEnum.CAN_TAKE.getCode());

            } else if (request.getTrainingRegistrationType().equals(TrainingRegistrationTypeEnum.CONTINUING_EDUCATION.name())) {
                wrapper.eq(DriverInfo::getContinuingEducationStatus, DriverRegistrationStatusEnum.exam_training_stage.name());
                wrapper.eq(DriverInfo::getContinuingEducationFlag, TrainingRegistrationFlagEnum.CAN_TAKE.getCode());
            } else if (request.getTrainingRegistrationType().equals(TrainingRegistrationTypeEnum.REPLACEMENT_REGISTRATION.name())) {
                wrapper.eq(DriverInfo::getReplacementRegistrationStatus, DriverRegistrationStatusEnum.exam_training_stage.name());
                wrapper.eq(DriverInfo::getReplacementRegistrationFlag, TrainingRegistrationFlagEnum.CAN_TAKE.getCode());
            }
        }
    }

    public void buildArchivalInfoSearchQuery(LambdaQueryWrapper<DriverInfo> wrapper, List<String> idCards) {
        if(CollUtil.isEmpty(idCards)){
            //查不到
            wrapper.eq(DriverInfo::getId,0L);
            return;
        }
        // 查询
        wrapper.in(DriverInfo::getIdCard, idCards)
                .orderByDesc(DriverInfo::getCreateOn)
                .isNotNull(DriverInfo::getCompanyId);
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildQuitInfoSearchQuery(LambdaQueryWrapper<DriverInfo> wrapper, ReqArchivalInfoSearchPO request) {
        // 获取入参
        String companyName = request.getCompanyName();
        String driverName = request.getDriverName();
        String idCard = request.getIdCard();
        // 查询
        wrapper.like(StringUtils.isNotBlank(companyName), DriverInfo::getCompanyName, companyName)
                .like(StringUtils.isNotBlank(driverName), DriverInfo::getDriverName, driverName)
                .eq(StringUtils.isNotBlank(idCard), DriverInfo::getIdCard, idCard)
                .eq(DriverInfo::getDriverStatus,DriverStatusEnum.quit.name())
                .orderByDesc(DriverInfo::getCreateOn);
    }

    public ResArchivalInfoDetailVO getDriverArchivalInfo(Long driverId) {
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        // 获取公司信息
        Long companyId = driverInfo.getCompanyId();
        CompanyDTO company = null;
        if (Objects.nonNull(companyId)) {
            company = companiesCacheHelper.getById(companyId);
        }
        // 装配返回信息
        ResArchivalInfoDetailVO resVo = new ResArchivalInfoDetailVO();
        resVo.setDriverId(driverInfo.getId());
        resVo.setDriverName(driverInfo.getDriverName());
        resVo.setDriverLicenseNo(driverInfo.getDriverLicenseNo());
        if (StringUtils.isNotBlank(driverInfo.getDriverLicenseType())) {
            List<String> strings = Arrays.stream(DriverLicenseTypeEnum.values()).map(String::valueOf).collect(Collectors.toList());
            if (strings.contains(driverInfo.getDriverLicenseType())) {
                resVo.setDriverLicenseType(DriverLicenseTypeEnum.valueOf(driverInfo.getDriverLicenseType()));
            }else {
                resVo.setDriverLicenseType(DriverLicenseTypeEnum.OTHER);
            }
        }
        if (StringUtils.isNotBlank(driverInfo.getMotorcycleTypeList())) {
            resVo.setMotorcycleTypeList(JSONObject.parseArray(driverInfo.getMotorcycleTypeList(), String.class));
        }

        // 对手机号和身份证号进行脱敏处理
        String phoneNo = driverInfo.getPhoneNo();
        String idCard = driverInfo.getIdCard();
        String encryptPhone = DesensitizedUtil.mobilePhone(phoneNo);
        String encryptIdCard = DesensitizedUtil.idCardNum(idCard, DriverConstant.ID_CARD_DESENSITIZED_FRONT, DriverConstant.ID_CARD_DESENSITIZED_END);
        resVo.setDriverPhoneNo(encryptPhone);
        resVo.setIdCard(encryptIdCard);

        String avatarFile = driverInfo.getAvatarFile();
        if (StringUtils.isNotBlank(avatarFile)) {
            resVo.setAvatarFile(JSONObject.parseObject(avatarFile, FileBasicInfo.class));
        }
        resVo.setBirth(driverInfo.getBirth());
        resVo.setNativePlace(driverInfo.getNativePlace());
        resVo.setDriverAddress(driverInfo.getAddress());
        resVo.setIllegalAndIllegalInfo(driverInfo.getIllegalAndIllegalInfo());
        resVo.setInitialLicenseTime(driverInfo.getInitialLicenseTime());
        resVo.setHealth(driverInfo.getHealth());
        resVo.setNativePlaceRegionCode(driverInfo.getNativePlaceRegionCode());
        resVo.setGender(driverInfo.getGender());
        if (Objects.nonNull(company)) {
            resVo.setCompanyId(company.getId());
            resVo.setCompanyName(company.getName());
            resVo.setCompanyAddress(company.getAddress());
            String contactPhone = company.getContactPhone();
            String encryptContactPhone = DesensitizedUtil.mobilePhone(contactPhone);
            resVo.setCompanyContactPhone(encryptContactPhone);
            resVo.setCompanyContactPerson(company.getContactPerson());
        }
        // 取证报名的信息作为驾驶员档案基本信息
        resVo.setTrainingRegistrationType(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION);

        // 装配初审信息
        TrainingRegistrationTypeEnum trainingRegistrationType = TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION;
        TrainingRegistrationReview preliminaryReviewInfo = iTrainingRegistrationReviewService.getOne(
                Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                        .eq(TrainingRegistrationReview::getRegistrationType, trainingRegistrationType.name())
                        .eq(TrainingRegistrationReview::getMetaApplyType, MetaApplyTypeEnum.PRELIMINARY_REVIEW.name())
                        .eq(TrainingRegistrationReview::getDriverUserId, driverInfo.getUserId())
                        .eq(TrainingRegistrationReview::getApprovalStatus, MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name()));
        if (Objects.nonNull(preliminaryReviewInfo)) {
            AuditInfo auditInfo = assemblerAuditInfo(preliminaryReviewInfo);
            resVo.setPreliminaryReviewInfo(auditInfo);

            assemblerAppendixInfo(resVo, preliminaryReviewInfo);
        }

        // 装配复核信息
        if (Objects.nonNull(preliminaryReviewInfo)
                && MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name().equals(preliminaryReviewInfo.getApprovalStatus())) {
            TrainingRegistrationReview inReviewInfo = iTrainingRegistrationReviewService.getOne(
                    Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                            .eq(TrainingRegistrationReview::getRegistrationType, trainingRegistrationType.name())
                            .eq(TrainingRegistrationReview::getMetaApplyType, MetaApplyTypeEnum.IN_REVIEW.name())
                            .eq(TrainingRegistrationReview::getDriverUserId, driverInfo.getUserId())
                            .eq(TrainingRegistrationReview::getApprovalStatus, MetaApplyStatusEnum.REEXAMINATION_APPROVED.name()));
            if (Objects.nonNull(inReviewInfo)) {
                AuditInfo auditInfo = assemblerAuditInfo(inReviewInfo);
                resVo.setReviewInfo(auditInfo);
            }
        }

        // 获取培训合格证信息
        Certificate certificate = certificateService.getOne(Wrappers.lambdaQuery(Certificate.class)
                .eq(Certificate::getDriverId, driverId)
                .orderBy(Boolean.TRUE, Boolean.TRUE, Certificate::getCreateOn)
                .last(DefValConstants.LIMIT_1));
        if (Objects.nonNull(certificate)){
            resVo.setCertificateNo(certificate.getCertificateNo());
        }
        resVo.setDriverUserId(driverInfo.getUserId());
        return resVo;
    }

    public ResArchivalInfoDetailVO getArchivalInfoReviewDetail(ReqGetArchivalInfoReviewDetailPO request) {
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        Long metaApplyId = request.getMetaApplyId();
        MetaApply metaApply = iMetaApplyService.getById(metaApplyId);
        VUtils.isTrue(Objects.isNull(metaApply)).throwMessage("审核记录不存在!");
        // 获取公司信息
        Long companyId = driverInfo.getCompanyId();
        CompanyDTO company = companiesCacheHelper.getById(companyId);
        // 装配返回信息
        ResArchivalInfoDetailVO resVo = new ResArchivalInfoDetailVO();
        resVo.setDriverId(driverInfo.getId());
        resVo.setDriverName(driverInfo.getDriverName());
        resVo.setDriverLicenseNo(driverInfo.getDriverLicenseNo());
        if (StringUtils.isNotBlank(driverInfo.getDriverLicenseType())) {
            resVo.setDriverLicenseType(DriverLicenseTypeEnum.valueOf(driverInfo.getDriverLicenseType()));
        }
        if (StringUtils.isNotBlank(driverInfo.getDriverLicenseType())) {
            resVo.setDriverLicenseType(DriverLicenseTypeEnum.valueOf(driverInfo.getDriverLicenseType()));
        }
        if (StringUtils.isNotBlank(driverInfo.getMotorcycleTypeList())) {
            resVo.setMotorcycleTypeList(JSONObject.parseArray(driverInfo.getMotorcycleTypeList(), String.class));
        }

        resVo.setDriverAddress(driverInfo.getAddress());

        // 对手机号和身份证号进行脱敏处理
        String phoneNo = driverInfo.getPhoneNo();
        String idCard = driverInfo.getIdCard();
        //String encryptPhone = DesensitizedUtil.mobilePhone(phoneNo);
        //String encryptIdCard = DesensitizedUtil.idCardNum(idCard, DriverConstant.ID_CARD_DESENSITIZED_FRONT, DriverConstant.ID_CARD_DESENSITIZED_END);
        //resVo.setDriverPhoneNo(encryptPhone);
        //resVo.setIdCard(encryptIdCard);
        resVo.setDriverPhoneNo(phoneNo);
        resVo.setIdCard(idCard);

        String avatarFile = driverInfo.getAvatarFile();
        if (StringUtils.isNotBlank(avatarFile)) {
            resVo.setAvatarFile(JSONObject.parseObject(avatarFile, FileBasicInfo.class));
        }
        resVo.setDriverAddress(driverInfo.getAddress());
        resVo.setBirth(driverInfo.getBirth());
        resVo.setNativePlace(driverInfo.getNativePlace());
        resVo.setHealth(driverInfo.getHealth());
        resVo.setGender(driverInfo.getGender());
        resVo.setCompanyId(company.getId());
        resVo.setCompanyName(company.getName());
        resVo.setCompanyAddress(company.getAddress());
        resVo.setCompanyContactPhone(company.getContactPhone());
        resVo.setCompanyContactPerson(company.getContactPerson());
        resVo.setTrainingRegistrationType(request.getTrainingRegistrationType());
        resVo.setNativePlaceRegionCode(driverInfo.getNativePlaceRegionCode());
        resVo.setInitialLicenseTime(driverInfo.getInitialLicenseTime());
        resVo.setIllegalAndIllegalInfo(driverInfo.getIllegalAndIllegalInfo());
        resVo.setDriverAddress(driverInfo.getAddress());
        resVo.setDriverPhoneNo(driverInfo.getPhoneNo());
        if (Objects.nonNull(metaApply.getJobChangeCompanyId())) {
            resVo.setJobChangeCompanyId(metaApply.getJobChangeCompanyId());
            CompanyDTO companyDto = companiesCacheHelper.getById(metaApply.getJobChangeCompanyId());
            resVo.setJobChangeCompanyName(companyDto.getName());
        }

        // 根据id获取当前查看的培训报名记录的信息
        Long reviewId = request.getTrainingRegistrationReviewId();

        TrainingRegistrationReview trainingRegistrationReview
                = iTrainingRegistrationReviewService.getById(reviewId);
        if (Objects.isNull(trainingRegistrationReview)) {
            throw new BizException("培训报名信息不存在!");
        }
        if (MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name()
                .equals(trainingRegistrationReview.getApprovalStatus())) {
            assemblerAppendixInfo(resVo, trainingRegistrationReview);
        }
        // 如果是材料初审信息-已初审列表中的数据或者是材料复审信息-待复核列表中的数据，获取审核详情
        if (MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name()
                .equals(trainingRegistrationReview.getApprovalStatus())
                || MetaApplyStatusEnum.FIRST_TRIAL_APPROVAL_REJECTION.name()
                .equals(trainingRegistrationReview.getApprovalStatus())
                || MetaApplyStatusEnum.REEXAMINATION_UNDER_REVIEW.name()
                .equals(trainingRegistrationReview.getApprovalStatus())) {
            // 装配初审信息
            AuditInfo auditInfo = assemblerAuditInfo(trainingRegistrationReview);
            resVo.setPreliminaryReviewInfo(auditInfo);
            // 装配附件信息
            assemblerAppendixInfo(resVo, trainingRegistrationReview);
        }
        // 材料复审列表中已复审列表中的数据，获取审核详情
        if (MetaApplyStatusEnum.REEXAMINATION_APPROVED.name()
                .equals(trainingRegistrationReview.getApprovalStatus())
                || MetaApplyStatusEnum.REEXAMINATION_APPROVAL_REJECTION.name()
                .equals(trainingRegistrationReview.getApprovalStatus())) {
            // 装配初审信息和复审信息
            // 获取该复审信息对应的初审报名信息(这两种状态下的复审信息对应的初审状态一定是审核通过的)
            Long preliminaryReviewId = trainingRegistrationReview.getPreliminaryReviewAssociatedId();
            TrainingRegistrationReview preliminaryTrainingRegistrationReview = iTrainingRegistrationReviewService.getById(preliminaryReviewId);
            // 装配初审信息
            AuditInfo preliminaryAuditInfo = assemblerAuditInfo(preliminaryTrainingRegistrationReview);
            resVo.setPreliminaryReviewInfo(preliminaryAuditInfo);
            assemblerAppendixInfo(resVo, preliminaryTrainingRegistrationReview);
            // 装配复审信息
            AuditInfo reviewAuditInfo = assemblerAuditInfo(trainingRegistrationReview);
            resVo.setReviewInfo(reviewAuditInfo);
        }

        return resVo;
    }

    private void assemblerAppendixInfo(ResArchivalInfoDetailVO resVo, TrainingRegistrationReview trainingRegistrationReview) {
        String appendixListJson = trainingRegistrationReview.getAppendixListJson();
        if (StringUtils.isNotBlank(appendixListJson)) {
            List<FileBasicInfo> appendixList = JSONObject.parseArray(appendixListJson, FileBasicInfo.class);
            resVo.setAppendixList(appendixList);
        }
    }

    /**
     * 只获取驾驶员基本信息
     *
     * @param request
     * @return ResArchivalInfoDetailVO
     */
    public ResArchivalInfoDetailVO getDriverDetail(ReqGetArchivalInfoReviewDetailPO request) {
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        // 获取公司信息
        Long companyId = driverInfo.getCompanyId();
        CompanyDTO company = companiesCacheHelper.getById(companyId);
        // 装配返回信息
        ResArchivalInfoDetailVO resVo = new ResArchivalInfoDetailVO();
        resVo.setDriverId(driverInfo.getId());
        resVo.setDriverName(driverInfo.getDriverName());
        resVo.setDriverLicenseNo(driverInfo.getDriverLicenseNo());
        if (StringUtils.isNotBlank(driverInfo.getDriverLicenseType())) {
            resVo.setDriverLicenseType(DriverLicenseTypeEnum.valueOf(driverInfo.getDriverLicenseType()));
        }
        resVo.setDriverPhoneNo(driverInfo.getPhoneNo());
        resVo.setDriverAddress(driverInfo.getAddress());
        resVo.setIdCard(driverInfo.getIdCard());
        String avatarFile = driverInfo.getAvatarFile();
        if (StringUtils.isNotBlank(avatarFile)) {
            resVo.setAvatarFile(JSONObject.parseObject(avatarFile, FileBasicInfo.class));
        }
        resVo.setBirth(driverInfo.getBirth());
        resVo.setNativePlace(driverInfo.getNativePlace());
        resVo.setHealth(driverInfo.getHealth());
        resVo.setGender(driverInfo.getGender());
        resVo.setCompanyId(company.getId());
        resVo.setCompanyName(company.getName());
        resVo.setCompanyAddress(company.getAddress());
        resVo.setCompanyContactPhone(company.getContactPhone());
        resVo.setCompanyContactPerson(company.getContactPerson());
        return resVo;
    }

    public AuditInfo assemblerAuditInfo(TrainingRegistrationReview trainingRegistrationReview) {
        Long metaApplyId = trainingRegistrationReview.getMetaApplyId();
        String auditAppendixListJson = trainingRegistrationReview.getAuditAppendixListJson();
        MetaApply metaApply = validateGetMetaApplyBySerializableId(metaApplyId);
        AuditInfo auditInfo = new AuditInfo();
        auditInfo.setAuditorId(metaApply.getApproverUserId());
        auditInfo.setAuditorName(metaApply.getApprover());
        auditInfo.setAuditTime(metaApply.getReviewTime());
        auditInfo.setReviewComments(metaApply.getAuditOpinion());
        if (StringUtils.isNotBlank(auditAppendixListJson)) {
            auditInfo.setAppendixList(JSONObject.parseArray(auditAppendixListJson, FileBasicInfo.class));
        }
        return auditInfo;
    }

    public void driverInduction(ReqDriverInductionPO request) {
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        Long newCompanyId = request.getNewCompanyId();
        Company newCompany = companyService.getById(newCompanyId);
        if ((Objects.isNull(newCompany))) {
            throw new BizException("公司信息不存在");
        }
        //驾驶员重新入职，将其关联到新的公司
        driverInfo.setCompanyId(newCompany.getId());
        driverInfo.setCompanyName(newCompany.getName());
        driverInfo.setRegionId(newCompany.getRegionId());
        driverInfo.setDriverStatus(DriverStatusEnum.induction.name());
        driverInfo.setInductionTime(LocalDateTime.now());
        driverInfo.setUpdateOn(LocalDateTime.now());
        iDriverInfoService.updateById(driverInfo);
    }

    /**
     * 装配驾驶员工作记录保存对象
     *
     * @param driverInfo
     * @return DriverWorkRecordInfo
     */
    private DriverWorkRecordInfo assembleDriverWorkRecordInfo(DriverInfo driverInfo) {
        DriverWorkRecordInfo driverWorkRecordInfo = new DriverWorkRecordInfo();
        driverWorkRecordInfo.setDriverId(driverInfo.getId());
        driverWorkRecordInfo.setDriverName(driverInfo.getDriverName());
        driverWorkRecordInfo.setAvatarFile(driverInfo.getAvatarFile());
        driverWorkRecordInfo.setGender(driverInfo.getGender());
        driverWorkRecordInfo.setIdCard(driverInfo.getIdCard());
        driverWorkRecordInfo.setBirth(driverInfo.getBirth());
        driverWorkRecordInfo.setNativePlace(driverInfo.getNativePlace());
        driverWorkRecordInfo.setNativePlaceRegionCode(driverInfo.getNativePlaceRegionCode());
        driverWorkRecordInfo.setPhoneNo(driverInfo.getPhoneNo());
        driverWorkRecordInfo.setHealth(driverInfo.getHealth());
        driverWorkRecordInfo.setAddress(driverInfo.getAddress());
        driverWorkRecordInfo.setDriverLicenseNo(driverInfo.getDriverLicenseNo());
        driverWorkRecordInfo.setDriverLicenseType(driverInfo.getDriverLicenseType());
        driverWorkRecordInfo.setCompanyId(driverInfo.getCompanyId());
        driverWorkRecordInfo.setCreateOn(LocalDateTime.now());
        driverWorkRecordInfo.setUpdateOn(LocalDateTime.now());
        driverWorkRecordInfo.setQuitTime(LocalDateTime.now());
        driverWorkRecordInfo.setReplacementRegistrationStatus(driverInfo.getReplacementRegistrationStatus());
        driverWorkRecordInfo.setContinuingEducationStatus(driverInfo.getContinuingEducationStatus());
        driverWorkRecordInfo.setMotorcycleTypeList(driverInfo.getMotorcycleTypeList());
        driverWorkRecordInfo.setDriverStatus(DriverStatusEnum.quit.name());
        driverWorkRecordInfo.setUserId(driverInfo.getUserId());
        driverWorkRecordInfo.setRegionId(driverInfo.getRegionId());
        driverWorkRecordInfo.setDriverRegistrationStatus(driverInfo.getDriverRegistrationStatus());
        driverWorkRecordInfo.setIllegalAndIllegalInfo(driverInfo.getIllegalAndIllegalInfo());
        driverWorkRecordInfo.setInitialLicenseTime(driverInfo.getInitialLicenseTime());
        CodeUtil.searchCompanyNameAndRegionName(driverWorkRecordInfo);
        return driverWorkRecordInfo;
    }

    public void driverQuit(Long driverId) {
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        // 驾驶员离职 更新驾驶员状态
        driverInfo.setDriverStatus(DriverStatusEnum.quit.name());
        driverInfo.setQuitTime(LocalDateTime.now());
        iDriverInfoService.updateById(driverInfo);
        // 删除驾驶员关联的企业和区域信息
        LambdaUpdateWrapper<DriverInfo> wrapper = Wrappers.lambdaUpdate(DriverInfo.class);
        wrapper.set(DriverInfo::getCompanyId,null)
                .set(DriverInfo::getCompanyName,null)
                .set(DriverInfo::getRegionId,null)
                .eq(DriverInfo::getId,driverInfo.getId());
        iDriverInfoService.update(wrapper);
        //保存驾驶员工作记录
        DriverWorkRecordInfo driverWorkRecordInfo = assembleDriverWorkRecordInfo(driverInfo);
        iDriverWorkRecordService.save(driverWorkRecordInfo);
    }

    public void changedJob(ReqChangedJobPO request) {
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        Long newCompanyId = request.getNewCompanyId();
        if (newCompanyId.equals(driverInfo.getCompanyId())) {
            throw new BizException("跳槽公司与当前公司相同，请重新选择!");
        }
        Company newCompany = companyService.getById(newCompanyId);
        if (Objects.isNull(newCompany)) {
            throw new BizException("公司信息不存在");
        }
        //保存跳槽前的工作记录
        DriverWorkRecordInfo driverWorkRecordInfo = assembleDriverWorkRecordInfo(driverInfo);
        iDriverWorkRecordService.save(driverWorkRecordInfo);
        //更新跳槽后的驾驶员档案信息
        driverInfo.setInductionTime(LocalDateTime.now());
        driverInfo.setCompanyId(newCompany.getId());
        driverInfo.setCompanyName(newCompany.getName());
        driverInfo.setRegionId(newCompany.getRegionId());
        driverInfo.setUpdateOn(LocalDateTime.now());
        driverInfo.setDriverStatus(DriverStatusEnum.induction.name());
        iDriverInfoService.updateById(driverInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    public void driverTrainingRegistration(ReqDriverTrainingRegistrationPO request) {
        // 获取培训报名类型
        TrainingRegistrationTypeEnum trainingRegistrationType = request.getTrainingRegistrationType();
        switch (trainingRegistrationType) {
            // 取证报名
            case FORENSIC_REGISTRATION: {
                forensicRegistration(request);
            }
            break;
            // 申请跳槽
            case JOB_APPLICATION: {
                jobApplication(request);
            }
            break;
            // 继续教育
            case CONTINUING_EDUCATION: {
                continuingEducation(request);
            }
            break;
            // 换证报名
            case REPLACEMENT_REGISTRATION: {
                replacementRegistration(request);
            }
            break;
            default:
                break;
        }
    }

    private void jobApplication(ReqDriverTrainingRegistrationPO request) {

        // 获取录入用户信息
        UserBasicInfoVO loginUser = userInfoHelper.getUserFullInfo();
        // 获取对应身份证驾驶员的用户ID
        Long driverUserId = request.getDriverUserId();
        VUtils.isTrue(Objects.isNull(driverUserId)).throwMessage("该身份证号驾驶员用户不存在!");
        // 校验提交的身份证号是否正确
        // 查询驾驶员信息
        DriverInfo driverInfo = driverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class).eq(DriverInfo::getUserId, driverUserId));
        VUtils.isTrue(Objects.isNull(driverInfo)).throwMessage("该身份证号驾驶员信息不存在!");
        String idCard = request.getIdCard();
        VUtils.isTrue(!driverInfo.getIdCard().equals(idCard)).throwMessage("请填写正确的身份证号!");
        // 校验该驾驶员是否可以进行跳槽申请
        String driverRegistrationStatus = driverInfo.getDriverRegistrationStatus();
        if (!DriverRegistrationStatusEnum.available.name().equals(driverRegistrationStatus)) {
            throw new BizException("请先通过驾驶员取证培训报名");
        }
        Long companyId = driverInfo.getCompanyId();
        Company company = companyService.getById(companyId);

        Long driverId = request.getDriverId();
        if (Objects.nonNull(driverId)){
            // 如果 driverId不为空则为修改信息(重新提交),必须审核状态为初审/复审阶段(驳回状态)时才能修改
            DriverInfo driver = validateGetDriverInfoBySerializableId(driverId);
            String jobChangeStatus = driver.getJobChangeStatus();
            boolean modifyAvailable =
                    DriverRegistrationStatusEnum.review_stage.name().equals(jobChangeStatus);
            if (!modifyAvailable) {
                // 只有驾驶员跳槽审核报名状态 为初审/复核阶段时 才能修改信息
                throw new BizException("当前状态不能重新提交跳槽申请!");
            }
            // 根据驾驶员id获取审核表信息及审核id,重新提交并更新审核状态
            updateApprovalStatus(request, driverId);
        }else {
            // 提交审核申请
            MetaApply metaApply = new MetaApply();
            metaApply.setCreateOn(LocalDateTime.now());
            metaApply.setUpdateOn(LocalDateTime.now());
            metaApply.setUserId(driverInfo.getUserId());
            metaApply.setApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            metaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            metaApply.setApplyTime(LocalDateTime.now());
            metaApply.setApplicantId(loginUser.getUserId());
            metaApply.setApplicant(loginUser.getNickName());
            metaApply.setRegionId(loginUser.getRegionId());
            metaApply.setCompanyId(loginUser.getCompanyId());
            JSONObject extraMaterial = new JSONObject();
            extraMaterial.put("driverInfoId", driverInfo.getId());
            metaApply.setExtraMaterial(NdJsonUtil.toJson(extraMaterial));
            metaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
            metaApply.setApplicantType(ApplicantTypeEnum.JOB_CHANGE_APPLICANT.getCode());
            metaApply.setJobChangeCompanyId(loginUser.getCompanyId());

            iMetaApplyService.save(metaApply);

            // 补充驾驶员报名审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            trainingRegistrationReviewSaveRecord.setMetaApplyId(metaApply.getId());
            trainingRegistrationReviewSaveRecord.setMetaApplyType(metaApply.getApplyType());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());

            // 填意向跳槽企业
            trainingRegistrationReviewSaveRecord.setCompanyId(loginUser.getCompanyId());
            trainingRegistrationReviewSaveRecord.setCompanyName(loginUser.getCompanyName());
            trainingRegistrationReviewSaveRecord.setRegionId(loginUser.getRegionId());

            trainingRegistrationReviewSaveRecord.setDriverUserId(driverInfo.getUserId());
            trainingRegistrationReviewSaveRecord.setDriverId(driverInfo.getId());
            trainingRegistrationReviewSaveRecord.setDriverIdCard(request.getIdCard());
            trainingRegistrationReviewSaveRecord.setDriverName(request.getDriverName());
            trainingRegistrationReviewSaveRecord.setDriverPhoneNo(request.getPhoneNo());
            trainingRegistrationReviewSaveRecord.setCreateBy(loginUser.getUserId());
            trainingRegistrationReviewSaveRecord.setCreateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setUpdateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord
                    .setRegistrationType(TrainingRegistrationTypeEnum.JOB_APPLICATION.name());
            List<FileBasicInfo> appendixList = request.getAppendixList();
            if (CollectionUtil.isNotEmpty(appendixList)) {
                trainingRegistrationReviewSaveRecord.setAppendixListJson(JSONObject.toJSONString(appendixList));
            }
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);

            // 更新驾驶员跳槽审核状态为审核阶段
            driverInfo.setJobChangeStatus(DriverJobChangeStatusEnum.review_stage.name());
            driverInfoService.updateById(driverInfo);
        }
        
    }


    /**
     * 驾驶员培训报名-未处理列表筛选(新接口)
     *
     * @return PageVo<ResDriverTrainingRegistrationListVO>
     */
    public PageVo<ResDriverTrainingRegistrationListVO> driverTrainingRegistrationUnDealList
    (ReqDriverTrainingRegistrationListPO request) {

        Integer pageNumber = request.getPageNumber();
        Integer pageSize = request.getPageSize();

        LambdaQueryWrapper<TrainingRegistrationReview> wrapper
                = Wrappers.lambdaQuery(TrainingRegistrationReview.class);
        DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
        context.buildDriverTrainingRegistrationUnDealQuery(wrapper, request);
        Page<TrainingRegistrationReview> page
                = iTrainingRegistrationReviewService.page(new Page<>(pageNumber, pageSize), wrapper);

        // 培训审核列表查询
        PageVo<ResDriverTrainingRegistrationListVO> pageVo = new PageVo<>();
        long total = page.getTotal();
        pageVo.setTotal(total);
        if (total == 0) {
            pageVo.setRecords(new ArrayList<>());
            return pageVo;
        }
        List<TrainingRegistrationReview> records = page.getRecords();
        List<ResDriverTrainingRegistrationListVO> returnVoList = records.stream().map(r -> {
            ResDriverTrainingRegistrationListVO resVo = new ResDriverTrainingRegistrationListVO();
            resVo.setTrainingRegistrationReviewId(r.getId());
            resVo.setCompanyId(r.getCompanyId());
            resVo.setCompanyName(r.getCompanyName());
            // 装配所属区域
            Long companyRegionId = r.getRegionId();
            if (Objects.nonNull(companyRegionId)) {
                String displayRegionName = regionsCacheHelper.getDisplayName(companyRegionId);
                resVo.setRegionId(companyRegionId);
                resVo.setRegionName(displayRegionName);
            }
            resVo.setDriverName(r.getDriverName());
            resVo.setDriverId(r.getDriverId());
            resVo.setMetaApplyId(r.getMetaApplyId());
            if (StringUtils.isNotBlank(r.getApprovalStatus())) {
                resVo.setMetaApplyStatus(MetaApplyStatusEnum.valueOf(r.getApprovalStatus()).name());
            }
            // 对驾驶员手机号和身份证号做脱敏处理
            String phoneNo = r.getDriverPhoneNo();
            String idCard = r.getDriverIdCard();
            String encryptPhone = DesensitizedUtil.mobilePhone(phoneNo);
            String encryptIdCard = DesensitizedUtil.idCardNum(idCard, DriverConstant.ID_CARD_DESENSITIZED_FRONT, DriverConstant.ID_CARD_DESENSITIZED_END);
            resVo.setPhoneNo(encryptPhone);
            resVo.setIdCard(encryptIdCard);
            resVo.setCreateTime(r.getCreateOn());
            resVo.setTrainingRegistrationType(TrainingRegistrationTypeEnum.valueOf(r.getRegistrationType()));
            return resVo;
        }).collect(Collectors.toList());
        pageVo.setRecords(returnVoList);
        return pageVo;
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildDriverTrainingRegistrationUnDealQuery(LambdaQueryWrapper<TrainingRegistrationReview> wrapper, ReqDriverTrainingRegistrationListPO request) {
        String companyName = request.getCompanyName();
        String driverName = request.getDriverName();
        MetaApplyTypeEnum metaApplyType = request.getMetaApplyType();
        TrainingRegistrationTypeEnum trainingRegistrationType = request.getTrainingRegistrationType();
        List<String> metaApplyStatusList = request.getMetaApplyStatusList();
        String metaApplyTypeStr = Objects.nonNull(metaApplyType) ? metaApplyType.name() : null;
        String trainingRegistrationTypeStr = Objects.nonNull(trainingRegistrationType) ? trainingRegistrationType.name() : null;
        wrapper.like(StringUtils.isNotBlank(companyName), TrainingRegistrationReview::getCompanyName, companyName)
                .like(StringUtils.isNotBlank(driverName), TrainingRegistrationReview::getDriverName, driverName)
                .eq(StringUtils.isNotBlank(metaApplyTypeStr), TrainingRegistrationReview::getMetaApplyType, metaApplyTypeStr)
                .eq(StringUtils.isNotBlank(trainingRegistrationTypeStr), TrainingRegistrationReview::getRegistrationType, trainingRegistrationTypeStr)
                .in(CollectionUtil.isNotEmpty(metaApplyStatusList), TrainingRegistrationReview::getApprovalStatus, metaApplyStatusList)
                .orderByDesc(TrainingRegistrationReview::getUpdateOn);
    }

    /**
     * 获取唯一的登陆username
     *
     * @param driverName
     * @return
     */
    private String generateNotDuplicateLoginIdentifier(String driverName) {
        String pinYinUserName = PinyinUtils.toPinyin(driverName);
        int count = 1;
        String returnUserName = pinYinUserName;
        while (true) {
            List<NdUserAuth> ndUserAuthList = iNdUserAuthService.list(Wrappers.lambdaQuery(NdUserAuth.class)
                    .eq(NdUserAuth::getIdentifier, returnUserName)
                    .eq(NdUserAuth::getAuthType, AuthTypeEnum.ACCOUNT_PASSWORD.name()));

            if (CollectionUtils.isEmpty(ndUserAuthList)) {
                return returnUserName;
            } else {
                returnUserName = pinYinUserName + count++;
            }
        }
    }

    /**
     * 生产密码
     *
     * @param phoneNo
     * @param driverName
     * @return
     */
    private String generateCredential(String phoneNo, String driverName) {
        String driverNamePinYin = PinyinUtils.toPinyin(driverName);
        String password = driverNamePinYin + phoneNo.substring(phoneNo.length() - 4);
        LOG.error("-------password : " + password);
        return passwordEncoder.encode(password);
    }

    private void continuingEducation(ReqDriverTrainingRegistrationPO request) {
        // 获取当前登陆账户id
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();
        // 校验驾驶员当前是否有继续教育审核的资格
        // 查询驾驶员信息
        String idCard = request.getIdCard();
        DriverInfo driverInfo = iDriverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getIdCard, idCard));
        if (Objects.isNull(driverInfo)) {
            throw new BizException("该驾驶员信息不存在");
        }
        // 校验驾驶员当前是否有继续教育的权限,只有取证报名完成状态下才能继续另外两种培训报名
        registrationAvailableCheckHelper.continuingEducationRegistrationValidCheck(request, driverInfo);

        Long driverId = request.getDriverId();
        if (Objects.nonNull(driverId)) {
            // 如果 driverId不为空则为修改信息(重新提交),必须审核状态为初审/复审阶段(驳回状态)时才能修改
            DriverInfo driver = validateGetDriverInfoBySerializableId(driverId);
            String continuingEducationStatus = driver.getContinuingEducationStatus();
            boolean modifyAvailable =
                    DriverRegistrationStatusEnum.review_stage.name().equals(continuingEducationStatus);
            if (!modifyAvailable) {
                // 只有驾驶员取证报名状态 为初审/复核阶段时 才能修改信息
                throw new BizException("当前状态不能修改驾驶员信息");
            }
            // 根据驾驶员id获取审核表信息及审核id,重新提交并更新审核状态
            updateApprovalStatus(request, driverId);
            // 校验 获取公司信息是否存在 获取当前登陆用户信息公司
            Long companyId = userInfoHelper.getUserCompanyId();
            DriverInfo newDriverInfo = assemblerSaveRecord(request);
            // 重新提交后,获取系统用户ID,装配驾驶员信息，更新驾驶员信息
            newDriverInfo.setContinuingEducationStatus(continuingEducationStatus);
            Long userId = iDriverInfoService.selectUserIdById(driverId);
            newDriverInfo.setUserId(userId);
            newDriverInfo.setId(driverInfo.getId());
            iDriverInfoService.updateById(newDriverInfo);
        } else {
            Company company = companyService.getById(driverInfo.getCompanyId());
            // 提交审核申请
            MetaApply metaApply = new MetaApply();
            metaApply.setCreateOn(LocalDateTime.now());
            metaApply.setUpdateOn(LocalDateTime.now());
            metaApply.setUserId(driverInfo.getUserId());
            metaApply.setApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            metaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            metaApply.setApplyTime(LocalDateTime.now());
            metaApply.setApplicantId(loginUser.getUserId());
            metaApply.setApplicant(loginUser.getNickName());
            metaApply.setRegionId(loginUser.getRegionId());
            metaApply.setCompanyId(loginUser.getCompanyId());
            JSONObject extraMaterial = new JSONObject();
            extraMaterial.put("driverInfoId", driverInfo.getId());
            metaApply.setExtraMaterial(NdJsonUtil.toJson(extraMaterial));
            metaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
            metaApply.setApplicantType(ApplicantTypeEnum.MATERIAL_APPLICANT.getCode());
            iMetaApplyService.save(metaApply);

            // 补充驾驶员报名审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            trainingRegistrationReviewSaveRecord.setMetaApplyId(metaApply.getId());
            trainingRegistrationReviewSaveRecord.setMetaApplyType(metaApply.getApplyType());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            trainingRegistrationReviewSaveRecord.setCompanyId(company.getId());
            trainingRegistrationReviewSaveRecord.setCompanyName(company.getName());
            trainingRegistrationReviewSaveRecord.setRegionId(company.getRegionId());
            trainingRegistrationReviewSaveRecord.setDriverUserId(driverInfo.getUserId());
            trainingRegistrationReviewSaveRecord.setDriverId(driverInfo.getId());
            trainingRegistrationReviewSaveRecord.setDriverIdCard(request.getIdCard());
            trainingRegistrationReviewSaveRecord.setDriverName(request.getDriverName());
            trainingRegistrationReviewSaveRecord.setDriverPhoneNo(request.getPhoneNo());
            trainingRegistrationReviewSaveRecord.setCreateBy(loginUser.getUserId());
            trainingRegistrationReviewSaveRecord.setCreateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setUpdateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord
                    .setRegistrationType(TrainingRegistrationTypeEnum.CONTINUING_EDUCATION.name());
            List<FileBasicInfo> appendixList = request.getAppendixList();
            if (CollectionUtil.isNotEmpty(appendixList)) {
                trainingRegistrationReviewSaveRecord.setAppendixListJson(JSONObject.toJSONString(appendixList));
            }
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);

            // 更新驾驶员状态
            driverInfo.setContinuingEducationStatus(DriverContinuingEducationRegistrationStatusEnum.review_stage.name());
            iDriverInfoService.updateById(driverInfo);
        }
    }

    private void replacementRegistration(ReqDriverTrainingRegistrationPO request) {
        // 获取当前登陆账户id
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();

        // 查询驾驶员信息
        String idCard = request.getIdCard();
        DriverInfo driverInfo = iDriverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getIdCard, idCard));
        if (Objects.isNull(driverInfo)) {
            throw new BizException("该驾驶员信息不存在");
        }
        // 校验驾驶员是否能参加换证报名培训
        registrationAvailableCheckHelper.replacementRegistrationValidCheck(request, driverInfo);
        Long driverId = request.getDriverId();
        if (Objects.nonNull(driverId)) {
            // 如果 driverId不为空则为修改信息(重新提交),必须审核状态为初审/复审阶段(驳回状态)时才能修改
            DriverInfo driver = validateGetDriverInfoBySerializableId(driverId);
            String replacementRegistrationStatus = driver.getReplacementRegistrationStatus();
            boolean modifyAvailable = DriverRegistrationStatusEnum.review_stage.name().equals(replacementRegistrationStatus);
            if (!modifyAvailable) {
                // 只有驾驶员换证报名状态 为初审/复核阶段时 才能修改信息
                throw new BizException("当前状态不能修改驾驶员信息");
            }
            //根据驾驶员id获取审核表信息及审核id，重新提交并更新审核状态
            updateApprovalStatus(request, driverId);
            // 校验 获取公司信息是否存在 获取当前登陆用户信息公司
            Long companyId = userInfoHelper.getUserCompanyId();
            DriverInfo newDriverInfo = assemblerSaveRecord(request);
            // 重新提交后,获取系统用户ID,装配驾驶员信息，更新驾驶员信息
            newDriverInfo.setReplacementRegistrationStatus(replacementRegistrationStatus);
            Long userId = iDriverInfoService.selectUserIdById(driverId);
            newDriverInfo.setUserId(userId);
            newDriverInfo.setId(driverInfo.getId());
            iDriverInfoService.updateById(newDriverInfo);
        } else {
            // 装配审核信息
            Company company = companyService.getById(driverInfo.getCompanyId());

            // 提交审核申请
            MetaApply metaApply = new MetaApply();
            metaApply.setCreateOn(LocalDateTime.now());
            metaApply.setUpdateOn(LocalDateTime.now());
            metaApply.setUserId(driverInfo.getUserId());
            metaApply.setApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            metaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            metaApply.setApplyTime(LocalDateTime.now());
            metaApply.setApplicantId(loginUser.getUserId());
            metaApply.setApplicant(loginUser.getNickName());
            metaApply.setRegionId(loginUser.getRegionId());
            metaApply.setCompanyId(loginUser.getCompanyId());
            JSONObject extraMaterial = new JSONObject();
            extraMaterial.put("driverInfoId", driverInfo.getId());
            metaApply.setExtraMaterial(NdJsonUtil.toJson(extraMaterial));
            metaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
            metaApply.setApplicantType(ApplicantTypeEnum.MATERIAL_APPLICANT.getCode());
            iMetaApplyService.save(metaApply);

            // 补充驾驶员报名审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            trainingRegistrationReviewSaveRecord.setMetaApplyId(metaApply.getId());
            trainingRegistrationReviewSaveRecord.setMetaApplyType(metaApply.getApplyType());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            trainingRegistrationReviewSaveRecord.setCompanyId(company.getId());
            trainingRegistrationReviewSaveRecord.setCompanyName(company.getName());
            trainingRegistrationReviewSaveRecord.setRegionId(company.getRegionId());
            trainingRegistrationReviewSaveRecord.setDriverUserId(driverInfo.getUserId());
            trainingRegistrationReviewSaveRecord.setDriverId(driverInfo.getId());
            trainingRegistrationReviewSaveRecord.setDriverIdCard(request.getIdCard());
            trainingRegistrationReviewSaveRecord.setDriverName(request.getDriverName());
            trainingRegistrationReviewSaveRecord.setDriverPhoneNo(request.getPhoneNo());
            trainingRegistrationReviewSaveRecord.setCreateBy(loginUser.getUserId());
            trainingRegistrationReviewSaveRecord.setCreateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setUpdateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setRegistrationType(TrainingRegistrationTypeEnum.REPLACEMENT_REGISTRATION.name());
            List<FileBasicInfo> appendixList = request.getAppendixList();
            if (CollectionUtil.isNotEmpty(appendixList)) {
                trainingRegistrationReviewSaveRecord.setAppendixListJson(JSONObject.toJSONString(appendixList));
            }
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);

            // 更新驾驶员状态
            driverInfo.setReplacementRegistrationStatus(DriverReplacementRegistrationStatusEnum.review_stage.name());
            iDriverInfoService.updateById(driverInfo);
        }
    }

    /**
     * 驾驶员培训报名(取证培训报名)
     *
     * @return
     */
    private void forensicRegistration(ReqDriverTrainingRegistrationPO request) {
        // 获取录入用户信息
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();

        Long driverId = request.getDriverId();
        if (Objects.nonNull(driverId)) {
            // 如果 driverId不为空则为修改信息(重新提交),必须审核状态为初审/复审阶段(驳回状态)时才能修改
            DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
            String driverRegistrationStatus = driverInfo.getDriverRegistrationStatus();
            boolean modifyAvailable = DriverRegistrationStatusEnum.review_stage.name().equals(driverRegistrationStatus);
            if (!modifyAvailable) {
                // 只有驾驶员取证报名状态 为初审/复核阶段时 才能修改信息
                throw new BizException("当前状态不能修改驾驶员信息");
            }
            //根据驾驶员id获取审核表信息及审核id,重新提交并更新审核状态
            updateApprovalStatus(request, driverId);
            // 校验 获取公司信息是否存在 获取当前登陆用户信息公司
            Long companyId = userInfoHelper.getUserCompanyId();
            DriverInfo newDriverInfo = assemblerSaveRecord(request);
            // 重新提交后,获取系统用户ID,装配驾驶员信息，更新驾驶员信息
            newDriverInfo.setDriverRegistrationStatus(driverRegistrationStatus);
            Long userId = iDriverInfoService.selectUserIdById(driverId);
            newDriverInfo.setUserId(userId);
            newDriverInfo.setId(driverInfo.getId());
            iDriverInfoService.updateById(newDriverInfo);
        } else {
            // 创建驾驶员信息
            // 校验驾驶员 手机号/身份证号是否可用
            String idCard = request.getIdCard();
            String phoneNo = request.getPhoneNo();
            validateDriverInfoIdCardAvailable(null, idCard);
            validateDriverInfoPhoneNoAvailable(null, phoneNo);
            // 校验 获取公司信息是否存在
            Long companyId = userInfoHelper.getUserCompanyId();
            CompanyDTO company = companiesCacheHelper.getById(companyId);

            // 创建唯一标识用户不可登陆用户账号 并获取用户id
            Long driverUserId = createUniqAccountAndGetUserId(request, loginUser.getUserId());

            // 装配驾驶员信息 保存驾驶员信息
            DriverInfo saveDriverInfoRecord = assemblerSaveRecord(request);
            saveDriverInfoRecord.setCreateOn(LocalDateTime.now());
            saveDriverInfoRecord.setUserId(driverUserId);
            saveDriverInfoRecord.setDriverRegistrationStatus(DriverRegistrationStatusEnum.review_stage.name());
            iDriverInfoService.save(saveDriverInfoRecord);

            driverId = saveDriverInfoRecord.getId();

            // 提交审核申请
            MetaApply metaApply = new MetaApply();
            metaApply.setCreateOn(LocalDateTime.now());
            metaApply.setUpdateOn(LocalDateTime.now());
            metaApply.setUserId(driverUserId);
            metaApply.setApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            metaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            metaApply.setApplyTime(LocalDateTime.now());
            metaApply.setApplicantId(loginUser.getUserId());
            metaApply.setApplicant(loginUser.getNickName());
            metaApply.setRegionId(loginUser.getRegionId());
            metaApply.setCompanyId(loginUser.getCompanyId());
            JSONObject extraMaterial = new JSONObject();
            extraMaterial.put("driverInfoId", driverId);
            metaApply.setExtraMaterial(NdJsonUtil.toJson(extraMaterial));
            metaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
            metaApply.setApplicantType(ApplicantTypeEnum.MATERIAL_APPLICANT.getCode());
            iMetaApplyService.save(metaApply);

            // 补充驾驶员报名审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            trainingRegistrationReviewSaveRecord.setMetaApplyId(metaApply.getId());
            trainingRegistrationReviewSaveRecord.setMetaApplyType(metaApply.getApplyType());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
            trainingRegistrationReviewSaveRecord.setCompanyId(companyId);
            trainingRegistrationReviewSaveRecord.setCompanyName(company.getName());
            trainingRegistrationReviewSaveRecord.setRegionId(company.getRegionId());
            trainingRegistrationReviewSaveRecord.setDriverUserId(driverUserId);
            trainingRegistrationReviewSaveRecord.setDriverId(driverId);
            trainingRegistrationReviewSaveRecord.setDriverIdCard(request.getIdCard());
            trainingRegistrationReviewSaveRecord.setDriverName(request.getDriverName());
            trainingRegistrationReviewSaveRecord.setDriverPhoneNo(request.getPhoneNo());
            trainingRegistrationReviewSaveRecord.setCreateBy(loginUser.getUserId());
            trainingRegistrationReviewSaveRecord.setCreateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setUpdateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setRegistrationType(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name());
            List<FileBasicInfo> appendixList = request.getAppendixList();
            if (CollectionUtil.isNotEmpty(appendixList)) {
                trainingRegistrationReviewSaveRecord.setAppendixListJson(JSONObject.toJSONString(appendixList));
            }
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);
        }

    }

    private void updateApprovalStatus(ReqDriverTrainingRegistrationPO request, Long driverId) {
        TrainingRegistrationReview firstTrailReview = iTrainingRegistrationReviewService.getOne(Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                .eq(TrainingRegistrationReview::getDriverId, driverId)
                .eq(TrainingRegistrationReview::getId, request.getTrainingRegistrationReviewId())
                .eq(TrainingRegistrationReview::getApprovalStatus, MetaApplyStatusEnum.FIRST_TRIAL_APPROVAL_REJECTION.name()));

        TrainingRegistrationReview reexaminationReview = iTrainingRegistrationReviewService.getOne(Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                .eq(TrainingRegistrationReview::getDriverId, driverId)
                .eq(TrainingRegistrationReview::getId, request.getTrainingRegistrationReviewId())
                .eq(TrainingRegistrationReview::getApprovalStatus, MetaApplyStatusEnum.REEXAMINATION_APPROVAL_REJECTION.name()));
        if (Objects.nonNull(firstTrailReview)) {
            Long firstTrailMetaApplyId = firstTrailReview.getMetaApplyId();
            //根据审核id获取审核状态
            MetaApply firstTrailMetaApply = iMetaApplyService.getOne(Wrappers.lambdaQuery(MetaApply.class)
                    .eq(MetaApply::getId, firstTrailMetaApplyId));
            //更新培训审核表信息，及审核意见表信息
            if (Objects.nonNull(firstTrailMetaApply) &&
                    MetaApplyStatusEnum.FIRST_TRIAL_APPROVAL_REJECTION.name().equals(firstTrailMetaApply.getApplyStatus())) {
                firstTrailMetaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
                firstTrailReview.setDriverIdCard(request.getIdCard());
                firstTrailReview.setDriverId(request.getDriverId());
                firstTrailReview.setDriverName(request.getDriverName());
                firstTrailReview.setDriverPhoneNo(request.getPhoneNo());
                firstTrailReview.setRegistrationType(request.getTrainingRegistrationType().name());
                firstTrailReview.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_UNDER_REVIEW.name());
                firstTrailReview.setCreateOn(LocalDateTime.now());
                firstTrailReview.setUpdateOn(LocalDateTime.now());
                List<FileBasicInfo> appendixList = request.getAppendixList();
                if (CollectionUtil.isNotEmpty(appendixList)) {
                    firstTrailReview.setAppendixListJson(JSONObject.toJSONString(appendixList));
                }
                iTrainingRegistrationReviewService.updateById(firstTrailReview);
                iMetaApplyService.updateById(firstTrailMetaApply);
            }
        }
        if (Objects.nonNull(reexaminationReview)) {
            Long reexaminationMetaApplyId = reexaminationReview.getMetaApplyId();
            MetaApply reexaminationMetaApply = iMetaApplyService.getOne(Wrappers.lambdaQuery(MetaApply.class)
                    .eq(MetaApply::getId, reexaminationMetaApplyId));
            if (Objects.nonNull(reexaminationMetaApply) &&
                    MetaApplyStatusEnum.REEXAMINATION_APPROVAL_REJECTION.name().equals(reexaminationMetaApply.getApplyStatus())) {
                reexaminationMetaApply.setApplyStatus(MetaApplyStatusEnum.REEXAMINATION_UNDER_REVIEW.name());
                reexaminationReview.setDriverIdCard(request.getIdCard());
                reexaminationReview.setDriverId(request.getDriverId());
                reexaminationReview.setDriverName(request.getDriverName());
                reexaminationReview.setDriverPhoneNo(request.getPhoneNo());
                reexaminationReview.setRegistrationType(request.getTrainingRegistrationType().name());
                reexaminationReview.setApprovalStatus(MetaApplyStatusEnum.REEXAMINATION_UNDER_REVIEW.name());
                reexaminationReview.setCreateOn(LocalDateTime.now());
                reexaminationReview.setUpdateOn(LocalDateTime.now());
                List<FileBasicInfo> appendixList = request.getAppendixList();
                if (CollectionUtil.isNotEmpty(appendixList)) {
                    reexaminationReview.setAppendixListJson(JSONObject.toJSONString(appendixList));
                }
                iTrainingRegistrationReviewService.updateById(reexaminationReview);
                iMetaApplyService.updateById(reexaminationMetaApply);
            }
        }
    }

    /**
     * 校验驾驶员身份证信息是否可用
     */
    private void validateDriverInfoIdCardAvailable(Long driverId, String idCard) {
        DriverInfo currentIdCardDriverInfo = iDriverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getIdCard, idCard)
                .ne(Objects.nonNull(driverId), DriverInfo::getId, driverId));
        if (Objects.nonNull(currentIdCardDriverInfo)) {
            throw new BizException("该驾驶员身份信息已录入");
        }
    }

    /**
     * 校验驾驶员手机号信息是否可用
     */
    private void validateDriverInfoPhoneNoAvailable(Long driverId, String phoneNo) {
        DriverInfo currentPhoneNoDriverInfo = iDriverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getPhoneNo, phoneNo)
                .ne(Objects.nonNull(driverId), DriverInfo::getId, driverId));
        if (Objects.nonNull(currentPhoneNoDriverInfo)) {
            throw new BizException("该驾驶员手机号信息已录入");
        }
    }

    /**
     * 根据公司id 校验获取公司信息
     *
     * @param companyId
     * @return
     */
    private Company validateGetCompanyBySerializableId(Long companyId) {
        Company company = companyService.getById(companyId);
        if (Objects.isNull(company)) {
            throw new BizException("公司信息不存在");
        }
        return company;
    }

    /**
     * 根据驾驶员id 校验获取驾驶员信息
     *
     * @return
     */
    private DriverInfo validateGetDriverInfoBySerializableId(Long driverId) {

        LambdaQueryWrapper<DriverInfo> wrapper = Wrappers.lambdaQuery(DriverInfo.class);
        DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
        context.buildQuery(wrapper, driverId);
        DriverInfo driverInfo = iDriverInfoService.getOne(wrapper);
        //DriverInfo driverInfo = iDriverInfoService.getById(driverId);
        if (Objects.isNull(driverInfo)) {
            throw new BizException("该驾驶员信息不存在");
        }
        return driverInfo;
    }

    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ALL)
    public void buildQuery(LambdaQueryWrapper<DriverInfo> wrapper, Long driverId) {
        wrapper.eq(DriverInfo::getId,driverId);
    }

    /**
     * 根据驾驶员id 校验获取审核信息
     *
     * @return
     */
    private MetaApply validateGetMetaApplyBySerializableId(Long metaApplyId) {
        MetaApply metaApply = iMetaApplyService.getById(metaApplyId);
        if (Objects.isNull(metaApply)) {
            throw new BizException("该审核信息不存在");
        }
        return metaApply;
    }

    /**
     * 根据驾驶员id 校验获取审核信息
     *
     * @return iTrainingRegistrationReviewService
     */
    private TrainingRegistrationReview validateGetTrainingRegistrationReviewByMetaApplyId(Long metaApplyId) {
        TrainingRegistrationReview trainingRegistrationReview = iTrainingRegistrationReviewService
                .getOne(Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                        .eq(TrainingRegistrationReview::getMetaApplyId, metaApplyId));
        if (Objects.isNull(trainingRegistrationReview)) {
            throw new BizException("该培训报名审核信息不存在");
        }
        return trainingRegistrationReview;
    }


    /**
     * 创建唯一标识用户不可登陆用户账号 并获取用户id
     *
     * @return
     */
    private Long createUniqAccountAndGetUserId(ReqDriverTrainingRegistrationPO request, Long createByUserId) {
        NdUserInfo driver = new NdUserInfo();
        driver.setCompanyId(userInfoHelper.getUserCompanyId());

        String phoneNo = request.getPhoneNo();
        NdUserInfo ndUserInfo = iNdUserInfoService.getOne(Wrappers.lambdaQuery(NdUserInfo.class)
                .eq(NdUserInfo::getMobile, phoneNo));
        if (Objects.nonNull(ndUserInfo)) {
            log.error("该手机号已有对应驾驶员{}", ndUserInfo.getUsername());
            throw new BizException("该手机号已有对应驾驶员,请更换手机号重新输入!");
        }
        driver.setMobile(request.getPhoneNo());
        driver.setNickName(request.getDriverName());
        driver.setUsername(request.getDriverName());
        driver.setCreateOn(LocalDateTime.now());
        driver.setUpdateOn(driver.getCreateOn());
        driver.setCreateBy(createByUserId);
        driver.setCanLogin(UserCanLoginEnum.CAN_NOT_LOGIN.getCode());
        iNdUserInfoService.save(driver);
        return driver.getId();
    }


    /**
     * 装配驾驶员信息saveRecord
     *
     * @param request
     * @return
     */
    private DriverInfo assemblerSaveRecord(ReqDriverTrainingRegistrationPO request) {
        DriverInfo saveRecord = new DriverInfo();
        saveRecord.setUpdateOn(LocalDateTime.now());
        saveRecord.setDriverName(request.getDriverName());
        saveRecord.setGender(request.getGender());
        saveRecord.setIdCard(request.getIdCard());
        saveRecord.setBirth(request.getBirth());
        saveRecord.setNativePlace(request.getNativePlace());
        saveRecord.setPhoneNo(request.getPhoneNo());
        saveRecord.setHealth(request.getHealth());
        saveRecord.setAddress(request.getAddress());
        saveRecord.setDriverLicenseNo(request.getDriverLicenseNo());
        saveRecord.setDriverLicenseType(request.getDriverLicenseType().name());
        saveRecord.setCompanyId(userInfoHelper.getUserCompanyId());
        CompanyDTO company = companiesCacheHelper.getById(userInfoHelper.getUserCompanyId());
        saveRecord.setCompanyName(userInfoHelper.getUserCompanyName());
        if (Objects.nonNull(company)) {
            saveRecord.setRegionId(company.getRegionId());
        }
        saveRecord.setNativePlaceRegionCode(request.getNativePlaceRegionCode());
        saveRecord.setInitialLicenseTime(request.getInitialLicenseTime());
        if (CollectionUtil.isNotEmpty(request.getMotorcycleTypeList())) {
            saveRecord.setMotorcycleTypeList(JSONObject.toJSONString(request.getMotorcycleTypeList()));
        }
        FileBasicInfo avatarFile = request.getAvatarFile();
        if (Objects.nonNull(avatarFile)) {
            saveRecord.setAvatarFile(JSONObject.toJSONString(avatarFile));
        }
        saveRecord.setIllegalAndIllegalInfo(request.getIllegalAndIllegalInfo());
        CodeUtil.searchCompanyName(saveRecord);
        return saveRecord;
    }


    @Transactional(rollbackFor = Exception.class)
    public void driverTrainingPreliminaryTrial(ReqDriverTrainingPreliminaryTrialPO request) {
        // 获取当前账号信息
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();
        // 获取入参信息
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        Long metaApplyId = request.getMetaApplyId();
        List<FileBasicInfo> appendixList = request.getAppendixList();
        Boolean result = request.getResult();
        // 获取审核表信息 培训审核表信息
        TrainingRegistrationReview trainingRegistrationReview = iTrainingRegistrationReviewService.getOne(Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                .eq(TrainingRegistrationReview::getMetaApplyId, metaApplyId));
        VUtils.isTrue(Objects.isNull(trainingRegistrationReview)).throwMessage("审核信息不存在!");
        MetaApply metaApply = iMetaApplyService.getOne(Wrappers.lambdaQuery(MetaApply.class)
                .eq(MetaApply::getId, metaApplyId));
        VUtils.isTrue(Objects.isNull(metaApply)).throwMessage("审核记录不存在!");
        String applyStatus;
        if (result) {
            applyStatus = MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name();
        } else {
            applyStatus = MetaApplyStatusEnum.FIRST_TRIAL_APPROVAL_REJECTION.name();
        }
        // 初审核结果处理
        metaApply.setApplyStatus(applyStatus);
        metaApply.setApproverUserId(loginUser.getUserId());
        metaApply.setApprover(loginUser.getNickName());
        metaApply.setAuditOpinion(request.getOpinion());
        metaApply.setReviewTime(LocalDateTime.now());
        metaApply.setUpdateOn(LocalDateTime.now());
        metaApply.setRegionId(loginUser.getRegionId());
        metaApply.setCompanyId(loginUser.getCompanyId());
        iMetaApplyService.saveOrUpdate(metaApply);

        //  更新 培训审核表信息
        trainingRegistrationReview.setApprovalStatus(applyStatus);
        if (CollectionUtil.isNotEmpty(appendixList)) {
            trainingRegistrationReview.setAuditAppendixListJson(JSONObject.toJSONString(appendixList));
        }
        iTrainingRegistrationReviewService.saveOrUpdate(trainingRegistrationReview);

        // 根据初审结果创建 复核审核
        if (result) {
            // 创建复审信息
            MetaApply inReviewMetaApply = new MetaApply();
            inReviewMetaApply.setCreateOn(LocalDateTime.now());
            inReviewMetaApply.setUpdateOn(LocalDateTime.now());
            inReviewMetaApply.setUserId(driverInfo.getUserId());
            inReviewMetaApply.setApplyType(MetaApplyTypeEnum.IN_REVIEW.name());
            inReviewMetaApply.setApplyStatus(MetaApplyStatusEnum.REEXAMINATION_UNDER_REVIEW.name());
            inReviewMetaApply.setApplyTime(LocalDateTime.now());
            inReviewMetaApply.setApplicantId(loginUser.getUserId());
            inReviewMetaApply.setApplicant(loginUser.getNickName());
            inReviewMetaApply.setRegionId(loginUser.getRegionId());
            inReviewMetaApply.setCompanyId(loginUser.getCompanyId());
            JSONObject inReviewExtraMaterial = new JSONObject();
            inReviewExtraMaterial.put("driverInfoId", driverId);
            inReviewMetaApply.setExtraMaterial(NdJsonUtil.toJson(inReviewExtraMaterial));
            inReviewMetaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
            if (ApplicantTypeEnum.MATERIAL_APPLICANT.getCode().equals(metaApply.getApplicantType())) {
                inReviewMetaApply.setApplicantType(ApplicantTypeEnum.MATERIAL_APPLICANT.getCode());
            }else if (ApplicantTypeEnum.JOB_CHANGE_APPLICANT.getCode().equals(metaApply.getApplicantType())){
                inReviewMetaApply.setApplicantType(ApplicantTypeEnum.JOB_CHANGE_APPLICANT.getCode());
                inReviewMetaApply.setJobChangeCompanyId(metaApply.getJobChangeCompanyId());
            }

            iMetaApplyService.save(inReviewMetaApply);

            // 创建复审
            // 补充驾驶员报名审核表信息

            Long jobChangeCompanyId = metaApply.getJobChangeCompanyId();
            String jobChangeCompanyName = null;
            Long jobChangeCompanyRegionId = null;
            if (Objects.nonNull(jobChangeCompanyId)) {
                CompanyDTO jobChangeCompany = companiesCacheHelper.getById(jobChangeCompanyId);
                jobChangeCompanyName = jobChangeCompany.getName();
                jobChangeCompanyRegionId = jobChangeCompany.getRegionId();
            }
            Integer applicantType = metaApply.getApplicantType();

            Long companyId = driverInfo.getCompanyId();
            CompanyDTO company = companiesCacheHelper.getById(companyId);

            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            trainingRegistrationReviewSaveRecord.setMetaApplyId(inReviewMetaApply.getId());
            trainingRegistrationReviewSaveRecord.setPreliminaryReviewAssociatedId(trainingRegistrationReview.getId());
            trainingRegistrationReviewSaveRecord.setMetaApplyType(MetaApplyTypeEnum.IN_REVIEW.name());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.REEXAMINATION_UNDER_REVIEW.name());

            // 如果是正常的驾驶员材料审核，培训审核表企业填写驾驶员所属企业
            if (ApplicantTypeEnum.MATERIAL_APPLICANT.getCode().equals(applicantType)) {
                trainingRegistrationReviewSaveRecord.setCompanyId(companyId);
                trainingRegistrationReviewSaveRecord.setCompanyName(company.getName());
                trainingRegistrationReviewSaveRecord.setRegionId(company.getRegionId());
            }
            // 如果是跳槽审核申请，培训审核表企业填写驾驶员意向跳槽企业
            else if (ApplicantTypeEnum.JOB_CHANGE_APPLICANT.getCode().equals(applicantType)) {
                trainingRegistrationReviewSaveRecord.setCompanyId(jobChangeCompanyId);
                trainingRegistrationReviewSaveRecord.setCompanyName(jobChangeCompanyName);
                trainingRegistrationReviewSaveRecord.setRegionId(jobChangeCompanyRegionId);
            }

            trainingRegistrationReviewSaveRecord.setDriverUserId(driverInfo.getUserId());
            trainingRegistrationReviewSaveRecord.setDriverId(driverId);
            trainingRegistrationReviewSaveRecord.setDriverIdCard(driverInfo.getIdCard());
            trainingRegistrationReviewSaveRecord.setDriverName(driverInfo.getDriverName());
            trainingRegistrationReviewSaveRecord.setDriverPhoneNo(driverInfo.getPhoneNo());
            trainingRegistrationReviewSaveRecord.setCreateBy(loginUser.getUserId());
            trainingRegistrationReviewSaveRecord.setCreateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setUpdateOn(LocalDateTime.now());
            trainingRegistrationReviewSaveRecord.setRegistrationType(request.getTrainingRegistrationType().name());
            trainingRegistrationReviewSaveRecord.setAppendixListJson(trainingRegistrationReview.getAppendixListJson());
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);
        }
    }

    public void driverTrainingInReview(ReqDriverInReviewingPO request) {
        // 获取当前账号信息
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();

        // 获取入参信息
        Long driverId = request.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);
        Long metaApplyId = request.getMetaApplyId();
        List<FileBasicInfo> appendixList = request.getAppendixList();
        Boolean result = request.getResult();

        // 获取审核表信息 培训审核表信息
        TrainingRegistrationReview trainingRegistrationReview = iTrainingRegistrationReviewService.getOne(Wrappers.lambdaQuery(TrainingRegistrationReview.class)
                .eq(TrainingRegistrationReview::getMetaApplyId, metaApplyId));
        VUtils.isTrue(Objects.isNull(trainingRegistrationReview)).throwMessage("审核信息不存在!");
        MetaApply metaApply = iMetaApplyService.getOne(Wrappers.lambdaQuery(MetaApply.class)
                .eq(MetaApply::getId, metaApplyId));
        VUtils.isTrue(Objects.isNull(metaApply)).throwMessage("审核记录不存在!");
        String applyStatus;
        if (result) {
            applyStatus = MetaApplyStatusEnum.REEXAMINATION_APPROVED.name();
        } else {
            applyStatus = MetaApplyStatusEnum.REEXAMINATION_APPROVAL_REJECTION.name();
        }

        // 初复核结果处理
        metaApply.setApplyStatus(applyStatus);
        metaApply.setApproverUserId(loginUser.getUserId());
        metaApply.setApprover(loginUser.getNickName());
        metaApply.setAuditOpinion(request.getOpinion());
        metaApply.setReviewTime(LocalDateTime.now());
        metaApply.setUpdateOn(LocalDateTime.now());
        metaApply.setRegionId(loginUser.getRegionId());
        metaApply.setCompanyId(loginUser.getCompanyId());
        iMetaApplyService.saveOrUpdate(metaApply);

        //  更新 培训审核表信息
        trainingRegistrationReview.setApprovalStatus(applyStatus);
        if (CollectionUtil.isNotEmpty(appendixList)) {
            trainingRegistrationReview.setAuditAppendixListJson(JSONObject.toJSONString(appendixList));
        }
        iTrainingRegistrationReviewService.saveOrUpdate(trainingRegistrationReview);


        // 如果是材料审核
        if (ApplicantTypeEnum.MATERIAL_APPLICANT.getCode().equals(metaApply.getApplicantType())) {
            // 根据复核结果  创建驾驶员账号 更新驾驶员信息
            if (result) {
                Long userId = driverInfo.getUserId();
                String phoneNo = driverInfo.getPhoneNo();
                String driverName = driverInfo.getDriverName();
                NdUserAuth userAuth = iNdUserAuthService.getOne(Wrappers.lambdaQuery(NdUserAuth.class).eq(NdUserAuth::getUserId, userId));
                NdUserAuth ndUserAuth = new NdUserAuth();
                if (Objects.nonNull(userAuth)) {
                    ndUserAuth.setId(userAuth.getId());
                }
                ndUserAuth.setCreateOn(LocalDateTime.now());
                ndUserAuth.setUpdateOn(LocalDateTime.now());
                ndUserAuth.setAuthType(AuthTypeEnum.ACCOUNT_PASSWORD.name());
                ndUserAuth.setIdentifier(phoneNo);
                //ndUserAuth.setCredential(generateCredential(phoneNo, driverName));
                ndUserAuth.setCredential(passwordEncoder.encode(UserLoginConstant.LOGIN_PASSWORD));
                ndUserAuth.setUserId(userId);
                iNdUserAuthService.saveOrUpdate(ndUserAuth);

                //将角色和驾驶员账号关联
                UserRole userRole = new UserRole();
                UserRole role = userRoleService.getOne(Wrappers.lambdaQuery(UserRole.class)
                        .eq(UserRole::getUserId, userId));
                if (Objects.nonNull(role)) {
                    userRole.setId(role.getId());
                }
                userRole.setUserId(userId);
                userRole.setRoleId(UserRoleTypeEnum.DRIVER_ROLE_ID.getId());
                userRoleService.saveOrUpdate(userRole);

                // 更新驾驶员信息
                if (TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name().equals(request.getTrainingRegistrationType().name())) {
                    driverInfo.setDriverRegistrationStatus(DriverRegistrationStatusEnum.exam_training_stage.name());
                    driverInfo.setDriverRegistrationFlag(TrainingRegistrationFlagEnum.CAN_TAKE.getCode());
                } else if (TrainingRegistrationTypeEnum.CONTINUING_EDUCATION.name().equals(request.getTrainingRegistrationType().name())) {
                    driverInfo.setContinuingEducationStatus(DriverRegistrationStatusEnum.exam_training_stage.name());
                    driverInfo.setContinuingEducationFlag(TrainingRegistrationFlagEnum.CAN_TAKE.getCode());
                } else if (TrainingRegistrationTypeEnum.REPLACEMENT_REGISTRATION.name().equals(request.getTrainingRegistrationType().name())) {
                    driverInfo.setReplacementRegistrationStatus(DriverRegistrationStatusEnum.exam_training_stage.name());
                    driverInfo.setReplacementRegistrationFlag(TrainingRegistrationFlagEnum.CAN_TAKE.getCode());
                }
                iDriverInfoService.saveOrUpdate(driverInfo);

                // 更新用户信息为可登录状态
                NdUserInfo userInfo = iNdUserInfoService.getById(userId);
                userInfo.setCanLogin(UserCanLoginEnum.CAN_LOGIN.getCode());
                userInfo.setUpdateOn(LocalDateTime.now());
                iNdUserInfoService.updateById(userInfo);
            }
        } else if (ApplicantTypeEnum.JOB_CHANGE_APPLICANT.getCode().equals(metaApply.getApplicantType())) {
            // 根据复核结果 更新驾驶员所属企业、所属区域、用户信息所属企业
            if (result){
                Long jobChangeCompanyId = metaApply.getJobChangeCompanyId();
                driverInfo.setCompanyId(jobChangeCompanyId);
                CompanyDTO companyDto = companiesCacheHelper.getById(jobChangeCompanyId);
                driverInfo.setCompanyName(companyDto.getName());
                driverInfo.setJobChangeStatus(DriverJobChangeStatusEnum.available.name());
                driverInfo.setRegionId(companyDto.getRegionId());
                driverInfoService.updateById(driverInfo);

                Long userId = driverInfo.getUserId();
                NdUserInfo userInfo = iNdUserInfoService.getById(userId);
                userInfo.setCompanyId(jobChangeCompanyId);
                iNdUserInfoService.updateById(userInfo);
            }
        }

    }


    public ResArchivalInfoDetailVO getDriverArchivalInfoByIdCard(String idCard) {
        // 查询驾驶员信息
        DriverInfo driverInfo = iDriverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getIdCard, idCard));
        if (Objects.isNull(driverInfo)) {
            throw new BizException("该驾驶员信息不存在");
        }
        return getDriverArchivalInfo(driverInfo.getId());
    }


    public List<NdVehicleViolationVO> getViolation(Long driverId, Integer violationType) {
        LambdaQueryWrapper<NdVehicleViolation> wrapper = Wrappers.lambdaQuery(NdVehicleViolation.class);
        wrapper.eq(NdVehicleViolation::getDriverId, driverId);
        wrapper.eq(NdVehicleViolation::getViolationType, violationType);
        List<NdVehicleViolation> list = vehicleViolationService.list(wrapper);

        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        return list.stream().map(w -> {
            NdVehicleViolationVO vo = BeanUtil.copyProperties(w, NdVehicleViolationVO.class);
            if (Objects.nonNull(vo.getViolationType())) {
                vo.setViolationTypeName(ViolationTypeEnum.getDescByCode(vo.getViolationType()));
            }
            if (Objects.nonNull(vo.getMissingCertificateType())) {
                vo.setMissingCertificateTypeName(MissCertEnum.getDescByCode(vo.getMissingCertificateType()));
            }
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        }).collect(Collectors.toList());
    }

    public List<NdVehicleAccidentVO> getAccidentVehicle(Long driverId) {

        LambdaQueryWrapper<NdVehicleGetOn> wrapper = Wrappers.lambdaQuery(NdVehicleGetOn.class);
        DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
        context.buildGetOnQuery(wrapper, driverId);
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(wrapper);
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentVO> page = vehicleAccidentManage.queryVehicleAccident(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ALL)
    public void buildGetOnQuery(LambdaQueryWrapper<NdVehicleGetOn> wrapper, Long driverId) {
        wrapper.eq(NdVehicleGetOn::getDriverId, driverId)
                .orderBy(Boolean.TRUE, Boolean.TRUE, NdVehicleGetOn::getUpdateOn)
                .last(" limit 1");
    }

    public List<NdVehicleAccidentVO> getAccidentVehicleOpen(Long driverId) {
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(Wrappers.lambdaQuery(NdVehicleGetOn.class)
                .eq(NdVehicleGetOn::getDriverId, driverId)
                .orderBy(Boolean.TRUE, Boolean.TRUE, NdVehicleGetOn::getUpdateOn)
                .last(" limit 1"));
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentVO> page = vehicleAccidentManage.queryVehicleAccidentOpen(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    public List<NdVehicleAccidentDeadVO> getAccidentDead(Long driverId) {

        LambdaQueryWrapper<NdVehicleGetOn> wrapper = Wrappers.lambdaQuery(NdVehicleGetOn.class);
        DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
        context.buildGetOnQuery(wrapper, driverId);
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(wrapper);
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentDeadVO> page = vehicleAccidentManage.queryDead(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentDeadVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentDeadVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    public List<NdVehicleAccidentDeadVO> getAccidentDeadOpen(Long driverId) {
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(Wrappers.lambdaQuery(NdVehicleGetOn.class)
                .eq(NdVehicleGetOn::getDriverId, driverId)
                .orderBy(Boolean.TRUE, Boolean.TRUE, NdVehicleGetOn::getUpdateOn)
                .last(" limit 1"));
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentDeadVO> page = vehicleAccidentManage.queryDeadOpen(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentDeadVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentDeadVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    public List<NdVehicleAccidentAnalysisVO> getAccidentAnalysis(Long driverId) {
        LambdaQueryWrapper<NdVehicleGetOn> wrapper = Wrappers.lambdaQuery(NdVehicleGetOn.class);
        DriverArchivesManage context = (DriverArchivesManage) AopContext.currentProxy();
        context.buildGetOnQuery(wrapper, driverId);
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(wrapper);
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentAnalysisVO> page = vehicleAccidentManage.queryAccidentAnalysis(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentAnalysisVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentAnalysisVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    public List<NdVehicleAccidentAnalysisVO> getAccidentAnalysisOpen(Long driverId) {
        NdVehicleGetOn getOn = vehicleGetOnService.getOne(Wrappers.lambdaQuery(NdVehicleGetOn.class)
                .eq(NdVehicleGetOn::getDriverId, driverId)
                .orderBy(Boolean.TRUE, Boolean.TRUE, NdVehicleGetOn::getUpdateOn)
                .last(" limit 1"));
        if (Objects.isNull(getOn)) {
            return Collections.emptyList();
        }
        AccidentPageQuery param = new AccidentPageQuery();
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        param.setCarPlate(getOn.getCarPlate());
        PageVo<NdVehicleAccidentAnalysisVO> page = vehicleAccidentManage.queryAccidentAnalysisOpen(param);
        if (0L == page.getTotal()) {
            return Collections.emptyList();
        }
        return CollUtils.convert(page.getRecords(), w -> {
            NdVehicleAccidentAnalysisVO vo = BeanUtil.copyProperties(w, NdVehicleAccidentAnalysisVO.class);
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
    }

    @Transactional(rollbackFor = Exception.class)
    public String importDriverArchivesData(ImportTemplateEnum template, MultipartFile file, HttpServletResponse response) {
        try (InputStream inputStream = file.getInputStream();
             ExcelReader reader = ExcelUtil.getReader(inputStream)) {
            Map<String, String> alias;
            List<String> title = ImportTemplateConstant.getTemplateTitle(template);
            alias = new HashMap<>(title.size());
            alias.put(title.get(0), "driverName");
            alias.put(title.get(1), "gender");
            alias.put(title.get(2), "idCard");
            alias.put(title.get(3), "birth");
            alias.put(title.get(4), "nativePlace");
            alias.put(title.get(5), "phoneNo");
            alias.put(title.get(6), "health");
            alias.put(title.get(7), "address");
            alias.put(title.get(8), "driverLicenseNo");
            alias.put(title.get(9), "driverLicenseType");
            alias.put(title.get(10), "initialLicenseTime");
            alias.put(title.get(11), "motorcycleTypeList");
            alias.put(title.get(12), "illegalAndIllegalInfo");
            reader.setHeaderAlias(alias);
            return importAndUpdateDriverArchivesData(response, reader.readAll(DriverArchivesDataImportDTO.class));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String importAndUpdateDriverArchivesData(HttpServletResponse response, List<DriverArchivesDataImportDTO> importDataList) {
        AtomicBoolean flag = new AtomicBoolean(true);
        StringBuffer stringBuffer = new StringBuffer();
        if (CollectionUtils.isEmpty(importDataList)) {
            return "导入数据为空,请重新导入!";
        }
        List<DriverInfo> driverArchivesDataList = new ArrayList<>();
        List<String> idCards = CollUtils.fieldList(importDataList, DriverArchivesDataImportDTO::getIdCard);
        Assert.isTrue(idCards.size() == importDataList.size(), "身份证号不可重复");
        Map<String, DriverInfo> driverInfoMap = iDriverInfoService.listByIdCard(idCards);
        Assert.isTrue(idCards.size() == driverInfoMap.size(), "请确保所有身份证号存在");
        LocalDateTime now = LocalDateTime.now();
        importDataList.forEach(w -> {
            String idCard = w.getIdCard();
            if (idCard == null) {
                throw new BizException("身份证号未填写，请填写后重新导入!");
            }
            DriverInfo driverInfo = driverInfoMap.get(w.getIdCard());

            if (driverInfo.getDriverRegistrationStatus().equals(DriverRegistrationStatusEnum.available.name()) ||
                    driverInfo.getReplacementRegistrationStatus().equals(DriverRegistrationStatusEnum.available.name()) ||
                    driverInfo.getContinuingEducationStatus().equals(DriverRegistrationStatusEnum.available.name())) {
                driverInfo.setDriverStatus(DriverStatusEnum.induction.name());
                //将导入驾驶员中完成培训的驾驶员导入结果标记为成功
                stringBuffer.append(driverInfo.getDriverName()).append("-").append(driverInfo.getIdCard()).append("-").append("导入成功").append("\n");
            } else {
                //将标志位设置为false提醒导入驾驶员中有未完成培训的驾驶员，并将导入结果标记为失败
                stringBuffer.append(driverInfo.getDriverName()).append("-").append(driverInfo.getIdCard()).append("-").append("导入失败!").append("\n");
                flag.set(false);
                return;
            }
            driverInfo.setCreateOn(now);
            driverInfo.setUpdateOn(now);
            driverInfo.setDriverName(w.getDriverName());

            driverInfo.setGender(GenderEnum.getByValue(w.getGender()).getCode());
            driverInfo.setIdCard(w.getIdCard());
            driverInfo.setBirth(w.getBirth());
            driverInfo.setNativePlace(w.getNativePlace());
            driverInfo.setPhoneNo(w.getPhoneNo());
            driverInfo.setHealth(w.getHealth());
            driverInfo.setAddress(w.getAddress());
            driverInfo.setDriverLicenseNo(w.getDriverLicenseNo());
            driverInfo.setDriverLicenseType(w.getDriverLicenseType());
            driverInfo.setIllegalAndIllegalInfo(w.getIllegalAndIllegalInfo());
            driverInfo.setInitialLicenseTime(w.getInitialLicenseTime());
            driverInfo.setMotorcycleTypeList(w.getMotorcycleTypeList());

            DriverInfo driverArchivesinfo = driverInfoMap.get(w.getIdCard());
            driverInfo.setId(driverArchivesinfo.getId());
            // 将现有驾驶员数据更新到导入企业下
            UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();
            driverInfo.setCompanyId(loginUser.getCompanyId());
            driverInfo.setCompanyName(loginUser.getCompanyName());
            driverInfo.setRegionId(loginUser.getRegionId());
            driverArchivesDataList.add(driverInfo);
        });
        iDriverInfoService.updateBatchById(driverArchivesDataList);

        //将导入结果字符串写入流中，供前端下载
        String importResult = stringBuffer.toString();
        byte[] bytes = importResult.getBytes();
        if (bytes.length > 0) {
            try {
                response.setContentType("application/octet-stream");
                response.setHeader("Content-disposition", "attachment;filename=导入结果.txt");
                response.setHeader("Content-Length", String.valueOf(bytes.length));
                response.getOutputStream().write(bytes);
                response.flushBuffer();
            } catch (IOException e) {
                log.error("流错误!");
            }
        }

        if (flag.get()) {
            return "全部导入成功!";
        } else {
            return "部分导入失败，详情请查看导入结果!";
        }
    }

    public void exportDriverArchives(HttpServletResponse response, ReqArchivalInfoSearchPO param) {
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<ResArchivalInfoSearchListVO> pageVo = archivalInfoSearch(param);
        List<DriverArchivesExportDTO> collect = pageVo.getRecords().stream().map(c -> {
            DriverArchivesExportDTO exportDTO = new DriverArchivesExportDTO();
            BeanUtils.copyProperties(c, exportDTO);
            String createTimeStr = NdDateUtils.format(c.getCreateTime(), NdDateUtils.DEFAULT_DATE_TIME_FORMAT);
            exportDTO.setCreateTime(createTimeStr);
            if (DriverStatusEnum.induction.name().equals(exportDTO.getDriverStatus())) {
                exportDTO.setDriverStatus("正常");
            } else if (DriverStatusEnum.quit.name().equals(exportDTO.getDriverStatus())) {
                exportDTO.setDriverStatus("离职");
            }
            return exportDTO;
        }).collect(Collectors.toList());

        String fileName = "驾驶员档案信息列表";
        ExcelDownUtil.setFileName(fileName, response);
        //数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), DriverArchivesExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 各市散办通过系统直接录入驾驶员相关信息
     *
     * @param param
     */
    public Boolean addDriverArchives(ReqAddDriverArchivesPO param) {
        //获取登录用户
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();

        // 校验驾驶员 手机号/身份证号是否可用
        String idCard = param.getIdCard();
        String phoneNo = param.getPhoneNo();
        validateDriverInfoIdCardAvailable(null, idCard);
        validateDriverInfoPhoneNoAvailable(null, phoneNo);
        // 校验 获取公司信息是否存在
        Long companyId = userInfoHelper.getUserCompanyId();
        // 创建唯一标识用户不可登陆用户账号 并获取用户id
        Long driverUserId = newCreateUniqAccountAndGetUserId(param, loginUser.getUserId());
        // 创建驾驶员可登录账号
        String driverName = param.getDriverName();
        NdUserAuth ndUserAuth = new NdUserAuth();
        ndUserAuth.setCreateOn(LocalDateTime.now());
        ndUserAuth.setUpdateOn(LocalDateTime.now());
        ndUserAuth.setAuthType(AuthTypeEnum.ACCOUNT_PASSWORD.name());
        ndUserAuth.setIdentifier(phoneNo);
        //ndUserAuth.setCredential(generateCredential(phoneNo, driverName));
        ndUserAuth.setCredential(passwordEncoder.encode(UserLoginConstant.LOGIN_PASSWORD));
        ndUserAuth.setUserId(driverUserId);
        iNdUserAuthService.save(ndUserAuth);

        //将角色和驾驶员账号关联
        UserRole userRole = new UserRole();
        userRole.setUserId(driverUserId);
        userRole.setRoleId(UserRoleTypeEnum.DRIVER_ROLE_ID.getId());
        userRoleService.save(userRole);

        // 装配驾驶员信息 保存驾驶员信息
        DriverInfo saveDriverInfoRecord = newAssemblerSaveRecord(param, companyId);
        if (param.getTrainingRegistrationType().name().equals(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name())) {
            saveDriverInfoRecord.setDriverRegistrationStatus(DriverRegistrationStatusEnum.available.name());
        }
        if (param.getTrainingRegistrationType().name().equals(TrainingRegistrationTypeEnum.REPLACEMENT_REGISTRATION.name())) {
            saveDriverInfoRecord.setDriverRegistrationStatus(DriverRegistrationStatusEnum.available.name());
            saveDriverInfoRecord.setReplacementRegistrationStatus(DriverRegistrationStatusEnum.available.name());
        }
        if (param.getTrainingRegistrationType().name().equals(TrainingRegistrationTypeEnum.CONTINUING_EDUCATION.name())) {
            saveDriverInfoRecord.setDriverRegistrationStatus(DriverRegistrationStatusEnum.available.name());
            saveDriverInfoRecord.setContinuingEducationStatus(DriverRegistrationStatusEnum.available.name());
        }
        saveDriverInfoRecord.setCreateOn(LocalDateTime.now());
        saveDriverInfoRecord.setUserId(driverUserId);
        saveDriverInfoRecord.setDriverStatus(DriverStatusEnum.induction.name());
        iDriverInfoService.save(saveDriverInfoRecord);

        Long driverId = saveDriverInfoRecord.getId();
        //生成合格证信息
        Certificate certificate = new Certificate();

        certificate.setDriverId(driverId);
        certificate.setUserId(driverUserId);
        certificate.setDriverName(driverName);
        certificate.setBirth(param.getBirth());
        certificate.setGender(param.getGender());
        certificate.setNativePlace(param.getNativePlace());
        certificate.setHealth(param.getHealth());
        certificate.setPhoneNo(param.getPhoneNo());
        certificate.setAddress(param.getAddress());
        certificate.setDriverLicenseType(param.getDriverLicenseType().name());
        certificate.setDriverLicenseNo(param.getDriverLicenseNo());
        certificate.setCertificateNo(param.getCertificateNo());
        certificate.setIssuedBy(param.getIssueBy());
        certificate.setIssueDate(param.getIssueDate());
        certificate.setExpiryDate(param.getExpiryDate());
        certificate.setRemark(param.getCertificateRemark());
        certificate.setRegionId(loginUser.getRegionId());
        certificate.setRegionName(loginUser.getRegionName());
        certificate.setCompanyId(loginUser.getCompanyId());
        certificate.setCompanyName(loginUser.getCompanyName());
        certificate.setCreateOn(LocalDateTime.now());
        certificate.setUpdateOn(LocalDateTime.now());
        certificate.setCreateBy(loginUser.getUserId());
        certificateService.save(certificate);
        //生成上车分数信息
        DriverScoreInfo driverScoreInfo = new DriverScoreInfo();
        driverScoreInfo.setCreateOn(LocalDateTime.now());
        driverScoreInfo.setCreateBy(loginUser.getUserId());
        driverScoreInfo.setUserId(driverUserId);
        driverScoreInfo.setDriverId(driverId);
        driverScoreInfo.setDriverScore(60);
        iDriverScoreInfoService.save(driverScoreInfo);
        return Boolean.TRUE;
    }

    /**
     * 装配驾驶员信息saveRecord
     *
     * @param request
     * @param request companyRegionId
     * @return newAssemblerSaveRecord
     */
    private DriverInfo newAssemblerSaveRecord(ReqAddDriverArchivesPO request, Long companyRegionId) {
        DriverInfo saveRecord = new DriverInfo();
        saveRecord.setUpdateOn(LocalDateTime.now());
        saveRecord.setDriverName(request.getDriverName());
        saveRecord.setGender(request.getGender());
        saveRecord.setIdCard(request.getIdCard());
        saveRecord.setBirth(request.getBirth());
        saveRecord.setNativePlace(request.getNativePlace());
        saveRecord.setPhoneNo(request.getPhoneNo());
        saveRecord.setHealth(request.getHealth());
        saveRecord.setAddress(request.getAddress());
        saveRecord.setDriverLicenseNo(request.getDriverLicenseNo());
        saveRecord.setDriverLicenseType(request.getDriverLicenseType().name());
        saveRecord.setCompanyId(userInfoHelper.getUserCompanyId());
        saveRecord.setCompanyName(userInfoHelper.getUserCompanyName());
        saveRecord.setRegionId(companyRegionId);
        saveRecord.setNativePlaceRegionCode(request.getNativePlaceRegionCode());
        saveRecord.setInitialLicenseTime(request.getInitialLicenseTime());
        if (CollectionUtil.isNotEmpty(request.getMotorcycleTypeList())) {
            saveRecord.setMotorcycleTypeList(JSONObject.toJSONString(request.getMotorcycleTypeList()));
        }
        FileBasicInfo avatarFile = request.getAvatarFile();
        if (Objects.nonNull(avatarFile)) {
            saveRecord.setAvatarFile(JSONObject.toJSONString(avatarFile));
        }
        saveRecord.setIllegalAndIllegalInfo(request.getIllegalAndIllegalInfo());
        return saveRecord;
    }

    /**
     * 创建唯一标识用户不可登陆用户账号 并获取用户id
     *
     * @return newCreateUniqAccountAndGetUserId
     */
    private Long newCreateUniqAccountAndGetUserId(ReqAddDriverArchivesPO request, Long createByUserId) {
        NdUserInfo driverUserInfo = new NdUserInfo();
        driverUserInfo.setCompanyId(userInfoHelper.getUserCompanyId());
        driverUserInfo.setMobile(request.getPhoneNo());
        driverUserInfo.setNickName(request.getDriverName());
        driverUserInfo.setUsername(request.getDriverName());
        driverUserInfo.setCreateOn(LocalDateTime.now());
        driverUserInfo.setUpdateOn(LocalDateTime.now());
        driverUserInfo.setCreateBy(createByUserId);
        iNdUserInfoService.save(driverUserInfo);
        return driverUserInfo.getId();
    }

    public ResArchivalInfoDetailVO modifyDriverBasicInfo(DriverBasicInfoDTO data) {

        Long driverId = data.getDriverId();
        // 获取驾驶员信息
        DriverInfo driverInfo = validateGetDriverInfoBySerializableId(driverId);

        // 装配返回信息,更新编辑信息
        ResArchivalInfoDetailVO resVo = new ResArchivalInfoDetailVO();

        // 更新编辑信息
        driverInfo.setDriverName(data.getDriverName());
        driverInfo.setGender(data.getGender());
        driverInfo.setBirth(data.getBirth());
        String idCard = data.getIdCard();
        // 身份证号经过编辑
        if (!idCard.contains(StrPool.ASTERISK)){
            // 校验身份证号
            boolean isValid = IdcardUtil.isValidCard(idCard);
            if (isValid) {
                driverInfo.setIdCard(idCard);
            }else {
                throw new BizException("身份证号输入错误,请重新输入!");
            }
        }
        driverInfo.setIdCard(data.getIdCard());
        driverInfo.setNativePlace(data.getNativePlace());
        driverInfo.setNativePlaceRegionCode(data.getNativePlaceRegionCode());
        FileBasicInfo file = data.getAvatarFile();
        if (Objects.nonNull(file)) {
            resVo.setAvatarFile(file);
            driverInfo.setAvatarFile(JSONObject.toJSONString(file));
        }
        driverInfo.setHealth(data.getHealth());
        driverInfo.setDriverLicenseNo(data.getDriverLicenseNo());
        driverInfo.setPhoneNo(data.getDriverPhoneNo());

        // 更新用户信息表中的驾驶员手机号
        Long userId = driverInfo.getUserId();
        if (Objects.nonNull(userId)) {
            NdUserInfo userInfo = iNdUserInfoService.getById(userId);
            String driverPhoneNo = data.getDriverPhoneNo();
            if (!driverPhoneNo.contains(StrPool.ASTERISK)) {
                // 校验手机号
                boolean isValid = Validator.isMobile(driverPhoneNo);
                if (isValid) {
                    userInfo.setMobile(driverPhoneNo);
                    iNdUserInfoService.updateById(userInfo);
                }else {
                    throw new BizException("手机号输入错误,请重新输入!");
                }
            }
        }
        driverInfo.setAddress(data.getDriverAddress());
        driverInfo.setDriverLicenseNo(data.getDriverLicenseNo());
        if (StringUtils.isNotBlank(data.getDriverLicenseType().name())) {
            resVo.setDriverLicenseType(data.getDriverLicenseType());
            driverInfo.setDriverLicenseType(data.getDriverLicenseType().name());
        }
        driverInfo.setInitialLicenseTime(data.getInitialLicenseTime());
        if (CollUtil.isNotEmpty(data.getMotorcycleTypeList())) {
            resVo.setMotorcycleTypeList(data.getMotorcycleTypeList());
            driverInfo.setMotorcycleTypeList(JSONObject.toJSONString(data.getMotorcycleTypeList()));
        }
        driverInfo.setIllegalAndIllegalInfo(data.getIllegalAndIllegalInfo());
        if (Objects.nonNull(data.getCompanyId())){
            CompanyDTO companyDto = companiesCacheHelper.getById(data.getCompanyId());
            if (Objects.isNull(companyDto)){
                throw new BizException("所属企业不存在!");
            }
            driverInfo.setCompanyId(companyDto.getId());
            driverInfo.setCompanyName(companyDto.getName());
            driverInfo.setRegionId(companyDto.getRegionId());
        }
        driverInfoService.updateById(driverInfo);

        return getResArchivalInfoDetailVO(data, driverId, resVo);
    }

    private ResArchivalInfoDetailVO getResArchivalInfoDetailVO(DriverBasicInfoDTO data, Long driverId, ResArchivalInfoDetailVO resVo) {
        resVo.setDriverId(driverId);
        resVo.setDriverName(data.getDriverName());

        resVo.setDriverAddress(data.getDriverAddress());

        // 对手机号和身份证号进行脱敏处理
        String phoneNo = data.getDriverPhoneNo();
        String idCard = data.getIdCard();
        String companyContactPhone = data.getCompanyContactPhone();
        String encryptPhone = DesensitizedUtil.mobilePhone(phoneNo);
        String encryptCompanyContactPhone = DesensitizedUtil.mobilePhone(companyContactPhone);
        String encryptIdCard = DesensitizedUtil.idCardNum(idCard, DriverConstant.ID_CARD_DESENSITIZED_FRONT, DriverConstant.ID_CARD_DESENSITIZED_END);
        resVo.setDriverPhoneNo(encryptPhone);
        resVo.setIdCard(encryptIdCard);
        resVo.setCompanyContactPhone(encryptCompanyContactPhone);

        resVo.setDriverLicenseNo(data.getDriverLicenseNo());
        resVo.setBirth(data.getBirth());
        resVo.setNativePlace(data.getNativePlace());
        resVo.setDriverAddress(data.getDriverAddress());
        resVo.setIllegalAndIllegalInfo(data.getIllegalAndIllegalInfo());
        resVo.setInitialLicenseTime(data.getInitialLicenseTime());
        resVo.setDriverPhoneNo(data.getDriverPhoneNo());
        resVo.setHealth(data.getHealth());
        resVo.setNativePlaceRegionCode(data.getNativePlaceRegionCode());
        resVo.setGender(data.getGender());
        resVo.setCompanyId(data.getCompanyId());
        if (Objects.nonNull(data.getCompanyId())) {
            CompanyDTO dto = companiesCacheHelper.getById(data.getCompanyId());
            if (Objects.nonNull(dto)) {
                resVo.setCompanyName(dto.getName());
            }
        }
        resVo.setCompanyAddress(data.getCompanyAddress());
        resVo.setCompanyContactPerson(data.getCompanyContactPerson());
        // 取证报名的信息作为驾驶员档案基本信息
        resVo.setTrainingRegistrationType(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION);
        return resVo;
    }
}
