rk
16 小时以前 3e210fac9492b90e21ca9bf76c1d9a8fda1f4388
server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -34,6 +34,8 @@
import com.doumee.dao.vo.DriverCancelLimitVO;
import com.doumee.dao.vo.DriverCenterVO;
import com.doumee.dao.vo.DriverGrabOrderVO;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.system.SystemUserService;
import com.doumee.dao.vo.DriverOrderDetailVO;
import com.doumee.core.utils.aliyun.AliSmsService;
import com.doumee.service.business.DriverInfoService;
@@ -115,6 +117,9 @@
    @Autowired
    private AreasBizImpl areasBiz;
    @Autowired
    private SystemUserService systemUserService;
    /**
     * 发送订单站内信通知
@@ -254,6 +259,10 @@
        if (pageWrap.getModel().getStatus() != null) {
            queryWrapper.eq(DriverInfo::getStatus, pageWrap.getModel().getStatus());
        }
        // 版本
        if (pageWrap.getModel().getVersionType() != null) {
            queryWrapper.eq(DriverInfo::getVersionType, pageWrap.getModel().getVersionType());
        }
        // 审批状态
        if (pageWrap.getModel().getAuditStatus() != null) {
            queryWrapper.eq(DriverInfo::getAuditStatus, pageWrap.getModel().getAuditStatus());
@@ -270,13 +279,7 @@
                .select(" ( select ifnull(sum(r.OPT_TYPE * r.AMOUNT),0) from revenue r where r.MEMBER_TYPE = 1 and r.MEMBER_ID= t.id and r.VAILD_STATUS = 1 ) as memberAmount ")
                .selectAs(Category::getName,DriverInfo::getCarTypeName)
                .leftJoin(Category.class, Category::getId,DriverInfo::getCarType);
        for (PageWrap.SortData sortData : pageWrap.getSorts()) {
            if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) {
                queryWrapper.orderByDesc(sortData.getProperty());
            } else {
                queryWrapper.orderByAsc(sortData.getProperty());
            }
        }
        queryWrapper.orderByDesc(DriverInfo::getId);
        PageData<DriverInfo> pageData = PageData.from(driverInfoMapper.selectPage(page, queryWrapper));
        for (DriverInfo d : pageData.getRecords()) {
            d.setGender(Constants.getGenderByIdCard(d.getIdcard()));
@@ -301,7 +304,9 @@
        String code = RandomStringUtils.randomNumeric(6);
        // 发送短信
        String templateParam = "{\"code\":\"" + code + "\"}";
        AliSmsService.sendSms(telephone, "SMS_491325122", templateParam);
        if (Constants.SmsNotify.VERIFY_CODE.isEnabled()) {
            AliSmsService.sendSms(telephone, Constants.SmsNotify.VERIFY_CODE.getTemplateCode(), templateParam);
        }
        // 保存短信记录
        Smsrecord smsrecord = new Smsrecord();
        smsrecord.setDeleted(Constants.ZERO);
@@ -355,7 +360,7 @@
        Date now = new Date();
        Member member;
        DriverInfo driverInfo = new DriverInfo();
        if (Objects.nonNull(existMember)) {
            // 已有司机账号,直接登录
            if (!Constants.equalsInteger(existMember.getStatus(), Constants.ZERO)) {
@@ -397,8 +402,6 @@
            memberMapper.insert(member);
            // 创建司机基础信息
            DriverInfo driverInfo = new DriverInfo();
            driverInfo.setId(member.getId());
            driverInfo.setDeleted(Constants.ZERO);
            driverInfo.setCreateTime(now);
            driverInfo.setUpdateTime(now);
@@ -407,12 +410,14 @@
            driverInfo.setMemberId(member.getId());
            driverInfo.setStatus(Constants.ZERO);
            driverInfo.setAuditStatus(99);
            driverInfo.setVersionType(Constants.ZERO);
            driverInfo.setJpushAlias(org.springframework.util.DigestUtils.md5DigestAsHex(telephone.getBytes()));
            driverInfoMapper.insert(driverInfo);
        }
        // 3. 生成token返回
        AccountResponse accountResponse = new AccountResponse();
        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(driverInfo.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
        accountResponse.setMember(member);
        return accountResponse;
    }
@@ -436,6 +441,13 @@
        if (!Constants.equalsInteger(member.getStatus(), Constants.ZERO)) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "账号已停用,请联系管理员");
        }
        // 获取司机表信息
        DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda().eq(DriverInfo::getMemberId, member.getId())
                .eq(DriverInfo::getDeleted, Constants.ZERO).eq(DriverInfo::getVersionType,Constants.ZERO).last("limit 1")
        );
        if(Objects.isNull(driverInfo)){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "司机账号不存在");
        }
        // 校验密码
        String encryptPwd = secure.encryptPassword(password, member.getSalt());
        if (!encryptPwd.equals(member.getPassword())) {
@@ -446,9 +458,8 @@
                .set(Member::getLoginTime, new Date())
                .setSql("login_times = login_times + 1")
                .eq(Member::getId, member.getId()));
        AccountResponse accountResponse = new AccountResponse();
        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
        accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(driverInfo.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
        accountResponse.setMember(member);
        return accountResponse;
    }
@@ -457,7 +468,7 @@
    @Override
    @Transactional
    public void submitVerify(Integer memberId, DriverVerifyRequest request) {
    public void submitVerify(Integer driverId, DriverVerifyRequest request) {
        // 参数基础校验
        if (StringUtils.isAnyBlank(request.getName(), request.getIdcard(), request.getLivePlace(),
                request.getCarCode(), request.getIdcardImg(), request.getIdcardImgBack())) {
@@ -469,19 +480,6 @@
        // 身份证号格式校验(18位,最后一位可为X)
        if (!request.getIdcard().matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$")) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "身份证号格式不正确");
        }
        // 查询司机信息
        DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (Objects.isNull(driverInfo)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // 状态校验:auditStatus=null(未提交)或auditStatus=2(审批驳回)可提交认证
        if (driverInfo.getAuditStatus() != null
                && !(Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.TWO)||Constants.equalsInteger(driverInfo.getAuditStatus(), 99))) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前状态不允许提交认证");
        }
        // 根据车辆类型判断是否需要驾驶证
        Category category = categoryMapper.selectById(request.getCarType());
@@ -512,8 +510,66 @@
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "其他资料照片最多上传3张");
        }
        // 更新司机信息
        // 查询正式版本司机
        DriverInfo official = driverInfoMapper.selectById(driverId);
        if (Objects.isNull(official) || Constants.equalsInteger(official.getDeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        Integer memberId = official.getMemberId();
        Date now = new Date();
        // 查询该会员最新的变更版本
        QueryWrapper<DriverInfo> changeQw = new QueryWrapper<>();
        changeQw.lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ONE)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .orderByDesc(DriverInfo::getCreateTime)
                .last("limit 1");
        DriverInfo changeVersion = driverInfoMapper.selectOne(changeQw);
        if (changeVersion == null) {
            // 首次认证:更新正式版本 + 创建变更版本
            applyDriverFieldsFromUpdate(official.getId(), request, now);
            deleteDriverAttachments(official.getId());
            saveDriverAttachments(official.getId(), request, now);
            // 重新读取更新后的正式版本,再创建变更版本
            DriverInfo updatedOfficial = driverInfoMapper.selectById(official.getId());
            createDriverChangeVersion(updatedOfficial, official.getId(), now);
        } else if (Constants.equalsInteger(changeVersion.getAuditStatus(), Constants.THREE)) {
            // auditStatus=3:生成新的变更版本
            Integer relationId = changeVersion.getRelationDriverId() != null
                    ? changeVersion.getRelationDriverId() : official.getId();
            DriverInfo newChange = new DriverInfo();
            applyDriverFieldsFromNew(newChange, request, official, now);
            newChange.setVersionType(Constants.ONE);
            newChange.setRelationDriverId(relationId);
            newChange.setAuditStatus(Constants.ZERO);
            newChange.setStatus(Constants.ZERO);
            newChange.setDeleted(Constants.ZERO);
            newChange.setCreateTime(now);
            newChange.setUpdateTime(now);
            newChange.setMemberId(memberId);
            newChange.setTelephone(official.getTelephone());
            newChange.setJpushAlias(official.getJpushAlias());
            driverInfoMapper.insert(newChange);
            saveDriverAttachments(newChange.getId(), request, now);
        } else {
            // auditStatus=0/2:直接更新变更版本
            applyDriverFieldsFromUpdate(changeVersion.getId(), request, now);
            deleteDriverAttachments(changeVersion.getId());
            saveDriverAttachments(changeVersion.getId(), request, now);
        }
        // 更新会员司机认证状态为认证中
        memberMapper.update(new UpdateWrapper<Member>().lambda()
                .set(Member::getBusinessStatus, Constants.ONE)
                .set(Member::getUpdateTime, now)
                .eq(Member::getId, memberId));
    }
    private void applyDriverFieldsFromUpdate(Integer driverId, DriverVerifyRequest request, Date now) {
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .set(DriverInfo::getName, request.getName())
                .set(DriverInfo::getIdcard, request.getIdcard())
@@ -533,39 +589,129 @@
                .set(DriverInfo::getAuditStatus, Constants.ZERO)
                .set(DriverInfo::getAuditRemark, null)
                .set(DriverInfo::getAuditTime, null)
                .eq(DriverInfo::getId, driverInfo.getId()));
                .eq(DriverInfo::getId, driverId));
    }
        // 删除旧的照片记录
        multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
                .eq(Multifile::getObjId, driverInfo.getId())
                .in(Multifile::getObjType, 6, 7, 8));
    private void applyDriverFieldsFromNew(DriverInfo driver, DriverVerifyRequest request, DriverInfo official, Date now) {
        driver.setName(request.getName());
        driver.setIdcard(request.getIdcard());
        driver.setMaritalStatus(request.getMaritalStatus());
        driver.setAreaId(request.getAreaId());
        driver.setLivePlace(request.getLivePlace());
        driver.setCarCode(request.getCarCode());
        driver.setCarType(request.getCarType());
        driver.setCarColor(request.getCarColor());
        driver.setCardStartDate(request.getCardStartDate());
        driver.setCardEndDate(request.getCardEndDate());
        driver.setIdcardImg(request.getIdcardImg());
        driver.setIdcardImgBack(request.getIdcardImgBack());
        driver.setAliAccount(request.getAliAccount());
        driver.setAliName(request.getAliName());
    }
        // 保存车辆照片 objType=6
        saveMultifileList(driverInfo.getId(), 6, request.getCarImgUrls(), now);
        // 保存驾驶证照片 objType=7
    private void saveDriverAttachments(Integer driverId, DriverVerifyRequest request, Date now) {
        saveMultifileList(driverId, 6, request.getCarImgUrls(), now);
        if (!CollectionUtils.isEmpty(request.getLicenseImgUrls())) {
            saveMultifileList(driverInfo.getId(), 7, request.getLicenseImgUrls(), now);
            saveMultifileList(driverId, 7, request.getLicenseImgUrls(), now);
        }
        // 保存其他资料照片 objType=8
        if (!CollectionUtils.isEmpty(request.getOtherImgUrls())) {
            saveMultifileList(driverInfo.getId(), 8, request.getOtherImgUrls(), now);
            saveMultifileList(driverId, 8, request.getOtherImgUrls(), now);
        }
    }
        // 更新会员司机认证状态为认证中
        memberMapper.update(new UpdateWrapper<Member>().lambda()
                .set(Member::getBusinessStatus, Constants.ONE)
                .set(Member::getUpdateTime, now)
                .eq(Member::getId, memberId));
    private void deleteDriverAttachments(Integer driverId) {
        multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
                .eq(Multifile::getObjId, driverId)
                .in(Multifile::getObjType, 6, 7, 8));
    }
    private void createDriverChangeVersion(DriverInfo official, Integer officialId, Date now) {
        DriverInfo change = new DriverInfo();
        change.setName(official.getName());
        change.setIdcard(official.getIdcard());
        change.setMaritalStatus(official.getMaritalStatus());
        change.setAreaId(official.getAreaId());
        change.setLivePlace(official.getLivePlace());
        change.setImgurl(official.getImgurl());
        change.setCarType(official.getCarType());
        change.setCarCode(official.getCarCode());
        change.setCarColor(official.getCarColor());
        change.setCardStartDate(official.getCardStartDate());
        change.setCardEndDate(official.getCardEndDate());
        change.setIdcardImg(official.getIdcardImg());
        change.setIdcardImgBack(official.getIdcardImgBack());
        change.setAliAccount(official.getAliAccount());
        change.setAliName(official.getAliName());
        change.setVersionType(Constants.ONE);
        change.setRelationDriverId(officialId);
        change.setMemberId(official.getMemberId());
        change.setTelephone(official.getTelephone());
        change.setOpenid(official.getOpenid());
        change.setUnionid(official.getUnionid());
        change.setJpushAlias(official.getJpushAlias());
        change.setScore(official.getScore());
        change.setDriverLevel(official.getDriverLevel());
        change.setBalance(official.getBalance());
        change.setTotalBalance(official.getTotalBalance());
        change.setLongitude(official.getLongitude());
        change.setLatitude(official.getLatitude());
        change.setAuditStatus(official.getAuditStatus());
        change.setStatus(official.getStatus());
        change.setDeleted(official.getDeleted());
        change.setCreateTime(now);
        change.setUpdateTime(now);
        driverInfoMapper.insert(change);
        // 拷贝附件
        List<Multifile> originFiles = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
                .eq(Multifile::getObjId, officialId)
                .eq(Multifile::getIsdeleted, Constants.ZERO)
                .in(Multifile::getObjType, 6, 7, 8));
        for (Multifile f : originFiles) {
            Multifile copy = new Multifile();
            copy.setCreator(f.getCreator());
            copy.setCreateDate(now);
            copy.setIsdeleted(Constants.ZERO);
            copy.setName(f.getName());
            copy.setInfo(f.getInfo());
            copy.setObjId(change.getId());
            copy.setType(f.getType());
            copy.setObjType(f.getObjType());
            copy.setFileurl(f.getFileurl());
            copy.setSortnum(f.getSortnum());
            multifileMapper.insert(copy);
        }
    }
    @Override
    public DriverInfo getVerifyDetail(Integer memberId) {
        // 优先查询最新的变更版本
        DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getId, memberId)
                .eq(DriverInfo::getRelationDriverId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ONE)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .orderByDesc(DriverInfo::getCreateTime)
                .last("limit 1"));
        if (Objects.isNull(driverInfo)) {
            // 无变更版本则查正式版本
            driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                    .eq(DriverInfo::getId, memberId)
                    .eq(DriverInfo::getVersionType, Constants.ZERO)
                    .eq(DriverInfo::getDeleted, Constants.ZERO)
                    .last("limit 1"));
        }
        if (Objects.isNull(driverInfo)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // 标记是否存在审批通过的正式版本
        if (driverInfo.getRelationDriverId() != null) {
            DriverInfo official = driverInfoMapper.selectById(driverInfo.getRelationDriverId());
            driverInfo.setHasApprovedOfficial(official != null
                    && Constants.equalsInteger(official.getAuditStatus(), Constants.THREE));
        } else if (Constants.equalsInteger(driverInfo.getVersionType(), Constants.ZERO)) {
            driverInfo.setHasApprovedOfficial(Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.THREE));
        } else {
            driverInfo.setHasApprovedOfficial(false);
        }
        // 拼接图片前缀
        String imgPrefix = "";
@@ -582,6 +728,7 @@
            if (Objects.nonNull(category)) {
                driverInfo.setCarTypeName(category.getName());
                driverInfo.setNeedLicense(Constants.equalsInteger(Integer.valueOf(category.getOtherField()), Constants.ONE) ? Constants.ONE : Constants.ZERO);
                driverInfo.setDriverType(category.getDetail());
            }
        }
        // 查询省市区信息
@@ -621,57 +768,142 @@
        if (Objects.isNull(auditDTO.getId()) || Objects.isNull(auditDTO.getAuditStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        DriverInfo driverInfo = driverInfoMapper.selectById(auditDTO.getId());
        if (Objects.isNull(driverInfo)) {
        // 审批的是变更版本
        DriverInfo changeVersion = driverInfoMapper.selectById(auditDTO.getId());
        if (Objects.isNull(changeVersion) || Constants.equalsInteger(changeVersion.getDeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // 只有审批状态为0(待审批)且已填写认证信息才能审批
        if (!Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.ZERO)
                || StringUtils.isBlank(driverInfo.getIdcard())) {
        if (!Constants.equalsInteger(changeVersion.getAuditStatus(), Constants.ZERO)
                || StringUtils.isBlank(changeVersion.getIdcard())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前状态不允许审批");
        }
        Date now = new Date();
        // 审批结果:auditDTO.auditStatus 0=通过→auditStatus=1,1=拒绝→auditStatus=2
        // auditDTO.auditStatus: 0=通过→3, 1=驳回→2
        Integer newAuditStatus;
        if (Constants.equalsInteger(auditDTO.getAuditStatus(), Constants.ZERO)) {
            newAuditStatus = Constants.THREE;  // 审批通过
            // 审批通过时司机定级为必填
            newAuditStatus = Constants.THREE;
            if (auditDTO.getDriverLevel() == null || auditDTO.getDriverLevel() < 1 || auditDTO.getDriverLevel() > 5) {
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "审批通过时必须填写司机定级");
            }
        } else if (Constants.equalsInteger(auditDTO.getAuditStatus(), Constants.ONE)) {
            newAuditStatus = Constants.TWO;  // 审批驳回
            newAuditStatus = Constants.TWO;
        } else {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "审批状态参数错误");
        }
        // 更新司机审批状态
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .set(DriverInfo::getAuditStatus, newAuditStatus)
                .set(DriverInfo::getAuditTime, now)
                .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
                .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
                .set(auditDTO.getDriverLevel() != null, DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
                .set(DriverInfo::getUpdateTime, now)
                .eq(DriverInfo::getId, auditDTO.getId()));
        // 更新会员司机认证状态:通过=2,驳回=3
        Integer driverStatus = Constants.equalsInteger(newAuditStatus, Constants.ONE) ? Constants.TWO : Constants.THREE;
        memberMapper.update(new UpdateWrapper<Member>().lambda()
                .set(Member::getBusinessStatus, driverStatus)
                .set(Member::getUpdateTime, now)
                .eq(Member::getId, driverInfo.getMemberId()));
        // 短信通知
        if (Constants.equalsInteger(newAuditStatus, Constants.ONE)) {
            // 审批通过
        // 查找正式版本
        Integer officialId = changeVersion.getRelationDriverId();
        DriverInfo official = officialId != null ? driverInfoMapper.selectById(officialId) : null;
        boolean hasApprovedOfficial = official != null
                && Constants.equalsInteger(official.getAuditStatus(), Constants.THREE);
        if (!hasApprovedOfficial) {
            // 场景1:正式版本未审批通过(首次审批)
            driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                    .set(DriverInfo::getAuditStatus, newAuditStatus)
                    .set(DriverInfo::getAuditTime, now)
                    .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
                    .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
                    .set(auditDTO.getDriverLevel() != null, DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
                    .set(DriverInfo::getUpdateTime, now)
                    .eq(DriverInfo::getId, changeVersion.getId()));
            // 同步更新正式版本(审批状态 + 数据字段)
            if (official != null) {
                syncDriverChangeToOfficial(changeVersion, official, auditDTO.getDriverLevel(), now);
            }
            // 更新会员状态
            Integer driverStatus = Constants.equalsInteger(newAuditStatus, Constants.THREE) ? Constants.TWO : Constants.THREE;
            memberMapper.update(new UpdateWrapper<Member>().lambda()
                    .set(Member::getBusinessStatus, driverStatus)
                    .set(Member::getUpdateTime, now)
                    .eq(Member::getId, changeVersion.getMemberId()));
            // 短信通知
            sendDriverAuditSms(changeVersion, newAuditStatus, auditDTO.getAuditRemark());
        } else {
            // 场景2:正式版本已审批通过(变更审批)
            if (Constants.equalsInteger(newAuditStatus, Constants.THREE)) {
                // 审批通过:变更版本标记auditStatus=3,同步数据到正式版本
                driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                        .set(DriverInfo::getAuditStatus, Constants.THREE)
                        .set(DriverInfo::getAuditTime, now)
                        .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
                        .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
                        .set(DriverInfo::getDriverLevel, auditDTO.getDriverLevel())
                        .set(DriverInfo::getUpdateTime, now)
                        .eq(DriverInfo::getId, changeVersion.getId()));
                // 同步变更版本数据到正式版本
                syncDriverChangeToOfficial(changeVersion, official, auditDTO.getDriverLevel(), now);
            } else {
                // 审批驳回:仅标记变更版本
                driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                        .set(DriverInfo::getAuditStatus, Constants.TWO)
                        .set(DriverInfo::getAuditTime, now)
                        .set(DriverInfo::getAuditRemark, auditDTO.getAuditRemark())
                        .set(DriverInfo::getAuditUser, auditDTO.getAuditUser())
                        .set(DriverInfo::getUpdateTime, now)
                        .eq(DriverInfo::getId, changeVersion.getId()));
            }
        }
    }
    private void syncDriverChangeToOfficial(DriverInfo changeVersion, DriverInfo official, Integer driverLevel, Date now) {
        official.setName(changeVersion.getName());
        official.setIdcard(changeVersion.getIdcard());
        official.setMaritalStatus(changeVersion.getMaritalStatus());
        official.setAreaId(changeVersion.getAreaId());
        official.setLivePlace(changeVersion.getLivePlace());
        official.setCarType(changeVersion.getCarType());
        official.setCarCode(changeVersion.getCarCode());
        official.setCarColor(changeVersion.getCarColor());
        official.setCardStartDate(changeVersion.getCardStartDate());
        official.setCardEndDate(changeVersion.getCardEndDate());
        official.setIdcardImg(changeVersion.getIdcardImg());
        official.setIdcardImgBack(changeVersion.getIdcardImgBack());
        official.setAliAccount(changeVersion.getAliAccount());
        official.setAliName(changeVersion.getAliName());
        if (driverLevel != null) {
            official.setDriverLevel(driverLevel);
        }
        official.setUpdateTime(now);
        driverInfoMapper.updateById(official);
        // 同步附件:先删正式版本旧附件,再从变更版本拷贝
        deleteDriverAttachments(official.getId());
        List<Multifile> changeFiles = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
                .eq(Multifile::getObjId, changeVersion.getId())
                .eq(Multifile::getIsdeleted, Constants.ZERO)
                .in(Multifile::getObjType, 6, 7, 8));
        for (Multifile f : changeFiles) {
            Multifile copy = new Multifile();
            copy.setCreator(f.getCreator());
            copy.setCreateDate(now);
            copy.setIsdeleted(Constants.ZERO);
            copy.setName(f.getName());
            copy.setInfo(f.getInfo());
            copy.setObjId(official.getId());
            copy.setType(f.getType());
            copy.setObjType(f.getObjType());
            copy.setFileurl(f.getFileurl());
            copy.setSortnum(f.getSortnum());
            multifileMapper.insert(copy);
        }
    }
    private void sendDriverAuditSms(DriverInfo driverInfo, Integer newAuditStatus, String auditRemark) {
        if (Constants.equalsInteger(newAuditStatus, Constants.THREE)) {
            sendSmsNotify(driverInfo.getTelephone(),
                    Constants.SmsNotify.DRIVER_AUTH_APPROVED,
                    "driver", driverInfo.getName());
        } else if (Constants.equalsInteger(newAuditStatus, Constants.TWO)) {
            // 审批驳回
            sendSmsNotify(driverInfo.getTelephone(),
                    Constants.SmsNotify.DRIVER_AUTH_REJECTED,
                    "driver", driverInfo.getName(),
                    "reason", auditDTO.getAuditRemark() != null ? auditDTO.getAuditRemark() : "");
                    "reason", auditRemark != null ? auditRemark : "");
        }
    }
@@ -716,7 +948,67 @@
                }
            }
        }
        // 查询审批人名称
        if (driverInfo.getAuditUser() != null) {
            try {
                SystemUser auditUser = systemUserService.findById(driverInfo.getAuditUser());
                if (auditUser != null) {
                    driverInfo.setAuditUserName(auditUser.getRealname());
                }
            } catch (Exception e) {
                // 审批人已删除等异常忽略
            }
        }
        return driverInfo;
    }
    @Override
    public DriverInfo updateDriverInfo(DriverVerifyRequest request) {
        Integer id = request.getId();
        if (id == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "司机主键不能为空");
        }
        DriverInfo driverInfo = driverInfoMapper.selectById(id);
        if (Objects.isNull(driverInfo) || Constants.equalsInteger(driverInfo.getDeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        Date now = new Date();
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .set(DriverInfo::getName, request.getName())
                .set(DriverInfo::getIdcard, request.getIdcard())
                .set(DriverInfo::getMaritalStatus, request.getMaritalStatus())
                .set(DriverInfo::getAreaId, request.getAreaId())
                .set(DriverInfo::getLivePlace, request.getLivePlace())
                .set(DriverInfo::getCarCode, request.getCarCode())
                .set(DriverInfo::getCarType, request.getCarType())
                .set(DriverInfo::getCarColor, request.getCarColor())
                .set(DriverInfo::getCardStartDate, request.getCardStartDate())
                .set(DriverInfo::getCardEndDate, request.getCardEndDate())
                .set(DriverInfo::getIdcardImg, request.getIdcardImg())
                .set(DriverInfo::getIdcardImgBack, request.getIdcardImgBack())
                .set(DriverInfo::getAliAccount, request.getAliAccount())
                .set(DriverInfo::getAliName, request.getAliName())
                .set(DriverInfo::getUpdateTime, now)
                .eq(DriverInfo::getId, id));
        // 删除旧的照片记录并保存新的
        multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
                .eq(Multifile::getObjId, id)
                .in(Multifile::getObjType,
                        Constants.FileType.DRIVER_CAR.getKey(),
                        Constants.FileType.DRIVER_LICENSE.getKey(),
                        Constants.FileType.DRIVER_OTHER.getKey()));
        if (!CollectionUtils.isEmpty(request.getCarImgUrls())) {
            saveMultifileList(id, Constants.FileType.DRIVER_CAR.getKey(), request.getCarImgUrls(), now);
        }
        if (!CollectionUtils.isEmpty(request.getLicenseImgUrls())) {
            saveMultifileList(id, Constants.FileType.DRIVER_LICENSE.getKey(), request.getLicenseImgUrls(), now);
        }
        if (!CollectionUtils.isEmpty(request.getOtherImgUrls())) {
            saveMultifileList(id, Constants.FileType.DRIVER_OTHER.getKey(), request.getOtherImgUrls(), now);
        }
        return getDetail(id);
    }
    @Override
@@ -765,7 +1057,8 @@
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
@@ -780,12 +1073,13 @@
    }
    @Override
    public void updateLocation(Integer memberId, Double longitude, Double latitude) {
    public void updateLocation(Integer driverId, Double longitude, Double latitude) {
        if (longitude == null || latitude == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "经纬度不能为空");
        }
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getId, driverId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
@@ -798,9 +1092,10 @@
    }
    @Override
    public DriverCenterVO getDriverCenterInfo(Integer memberId) {
    public DriverCenterVO getDriverCenterInfo(Integer driveId) {
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getId, driveId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
@@ -812,6 +1107,7 @@
        vo.setCarCode(driver.getCarCode());
        vo.setScore(driver.getScore() != null ? driver.getScore().toPlainString() : "0");
        vo.setDriverLevel(driver.getDriverLevel());
        vo.setDriverLevelName(Constants.getDriverLevelName(driver.getDriverLevel()));
        vo.setAuditStatus(driver.getAuditStatus());
        vo.setAuditRemark(driver.getAuditRemark());
        vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L);
@@ -822,8 +1118,11 @@
                    + systemDictDataBiz.queryByCode(Constants.OSS, Constants.MEMBER_FILES).getCode();
            vo.setFullImgUrl(imgPrefix + driver.getImgurl());
        }
        // 今日预计佣金:revenue表中今天的收入记录金额之和
        Category category = categoryMapper.selectById(driver.getCarType());
        if(Objects.nonNull(category)&&StringUtils.isNotBlank(category.getDetail())){
            vo.setDriverType(category.getDetail());
        }
        // 今日预计佣金:今日接单的司机佣金 + 平台奖励金
        Date now = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(now);
@@ -833,16 +1132,16 @@
        cal.set(Calendar.MILLISECOND, 0);
        Date todayStart = cal.getTime();
        QueryWrapper<Revenue> revenueWrapper = new QueryWrapper<>();
        revenueWrapper.lambda()
                .eq(Revenue::getMemberId, memberId)
                .eq(Revenue::getMemberType, Constants.ONE)
                .eq(Revenue::getOptType, Constants.ONE)
                .eq(Revenue::getDeleted, Constants.ZERO)
                .ge(Revenue::getCreateTime, todayStart);
        revenueWrapper.select("IFNULL(SUM(AMOUNT),0) as amount");
        Revenue sumResult = revenueMapper.selectOne(revenueWrapper);
        vo.setTodayCommission(sumResult != null && sumResult.getAmount() != null ? sumResult.getAmount() : 0L);
        QueryWrapper<Orders> commissionWrapper = new QueryWrapper<>();
        commissionWrapper.lambda()
                .eq(Orders::getAcceptDriver, driver.getId())
                .eq(Orders::getDeleted, Constants.ZERO)
                .ge(Orders::getAcceptTime, todayStart);
        commissionWrapper.select("IFNULL(SUM(DRIVER_FEE),0) as driverFee", "IFNULL(SUM(PLATFORM_REWARD_AMOUNT),0) as platformRewardAmount");
        Orders commissionResult = ordersMapper.selectOne(commissionWrapper);
        long driverFee = commissionResult != null && commissionResult.getDriverFee() != null ? commissionResult.getDriverFee() : 0L;
        long rewardAmount = commissionResult != null && commissionResult.getPlatformRewardAmount() != null ? commissionResult.getPlatformRewardAmount() : 0L;
        vo.setTodayCommission(driverFee + rewardAmount);
        // 今日接单数:今天完成的订单数(acceptDriver=司机主键,状态=已完成)
        Long todayOrderCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
@@ -872,6 +1171,7 @@
    public com.doumee.dao.vo.DriverStatsVO getDriverStats(Integer memberId) {
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
@@ -922,7 +1222,8 @@
        // 1. 获取司机定位
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null || driver.getLatitude() == null || driver.getLongitude() == null) {
@@ -966,7 +1267,7 @@
                .select("c2.other_field as c2OtherField")
                .select("c2.name as goodLevelName")
                // 是否存在特大尺寸
                .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized")
                .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.detail = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized")
                // JOIN
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0")
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0")
@@ -1046,7 +1347,8 @@
        // 获取司机信息
        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getMemberId, memberId)
                .eq(DriverInfo::getId, memberId)
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (driver == null) {
@@ -1064,19 +1366,27 @@
                .select("s1.address", Orders::getDepositShopAddress)
                .select("s2.name", Orders::getTakeShopName)
                .select("s2.address", Orders::getTakeShopAddress)
                .select("s1.link_phone", Orders::getDepositShopLinkPhone)
                .select("s2.link_phone as takeShopLinkPhone")
                .select("c2.other_field as c2OtherField")
                .select("c2.name as goodLevelName")
                .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized")
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0")
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0")
                .leftJoin("category c1 on c1.id = t.GOOD_TYPE and c1.DELETED = 0")
                .leftJoin("category c2 on c2.id = c1.RELATION_ID and c2.DELETED = 0 and c2.TYPE = 3")
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID ")
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID    ")
                .leftJoin("category c1 on c1.id = t.GOOD_TYPE   ")
                .leftJoin("category c2 on c2.id = c1.RELATION_ID and  c2.TYPE = 3")
                .eq(Orders::getAcceptDriver, driver.getId())
                .eq(Orders::getType, Constants.ONE)
                .eq(Objects.nonNull(dto.getStatus()),Orders::getStatus, dto.getStatus())
                .eq(Orders::getDeleted, Constants.ZERO)
                .orderByAsc(Orders::getAcceptTime);
        // 关键词搜索:收件人/收件人电话模糊、订单号精准
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            String kw = dto.getKeyword().trim();
            wrapper.and(w -> w.like(Orders::getTakeUser, kw)
                    .or().like(Orders::getTakePhone, kw)
                    .or().eq(Orders::getCode, kw));
        }
        List<Orders> ordersList = ordersMapper.selectJoinList(Orders.class, wrapper);
@@ -1109,11 +1419,11 @@
        wrapper.selectAll(Orders.class)
                .select("s1.name", Orders::getDepositShopName)
                .select("s1.address", Orders::getDepositShopAddress)
                .select("s1.telephone", Orders::getDepositShopLinkPhone)
                .select("s1.link_phone", Orders::getDepositShopLinkPhone)
                .select("s2.name", Orders::getTakeShopName)
                .select("s2.address", Orders::getTakeShopAddress)
                .select("s2.telephone", Orders::getTakeShopLinkPhone)
                .select("c2.other_field as c2OtherField")
                .select("s2.link_phone", Orders::getTakeShopLinkPhone)
                .select("c1.other_field as c2OtherField")
                .select("c1.name as goodTypeName")
                .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized")
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0")
@@ -1418,6 +1728,7 @@
        // 7. 通知会员:司机已抢单
        sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_GRABBED, orderId,
                "orderNo", order.getCode(),
                "driverName", driver.getName());
        // 通知存件门店:订单已抢单待取件
@@ -1726,17 +2037,15 @@
            vo.setDepositDistance(formatDistance(distKm));
        }
        // 取件信息 + 联系电话(使用Orders自带坐标)
        // 取件信息(使用Orders自带坐标)
        boolean hasTakeShop = order.getTakeShopId() != null && StringUtils.isNotBlank(order.getTakeShopName());
        if (hasTakeShop) {
            vo.setTakeName(order.getTakeShopName());
            vo.setTakeAddress(order.getTakeShopAddress());
            vo.setTakeShopId(order.getTakeShopId());
            vo.setContactPhone(order.getTakeShopLinkPhone());
        } else {
            vo.setTakeName(order.getTakeLocation());
            vo.setTakeAddress(order.getTakeLocationRemark());
            vo.setContactPhone(order.getTakePhone());
        }
        vo.setTakeLng(order.getTakeLgt() != null ? order.getTakeLgt().doubleValue() : null);
        vo.setTakeLat(order.getTakeLat() != null ? order.getTakeLat().doubleValue() : null);
@@ -1761,6 +2070,19 @@
        vo.setStatus(order.getStatus());
        vo.setStatusDesc(getStatusDesc(order.getStatus()));
        vo.setCreateTime(order.getCreateTime());
        // 联系电话(按订单状态)
        if (Constants.equalsInteger(order.getStatus(), Constants.THREE)) {
            vo.setContactPhone(order.getDepositShopLinkPhone());
        } else if (Constants.equalsInteger(order.getStatus(), Constants.FOUR)) {
            if (hasTakeShop) {
                vo.setContactPhone(order.getTakeShopLinkPhone());
            } else {
                vo.setContactPhone(order.getTakePhone());
            }
        } else if (Constants.equalsInteger(order.getStatus(), Constants.FIVE)) {
            vo.setContactPhone(order.getTakePhone());
        }
        // 物品明细
        List<OrdersDetail> details = detailMap.getOrDefault(order.getId(), Collections.emptyList());
@@ -1798,25 +2120,25 @@
        if (StringUtils.isBlank(phone)) {
            return;
        }
        if (!smsNotify.isEnabled()) {
            return;
        }
        String content = smsNotify.format(paramPairs);
        try {
            JSONObject templateParam = new JSONObject();
            for (int i = 0; i < paramPairs.length - 1; i += 2) {
                templateParam.put(paramPairs[i], paramPairs[i + 1]);
            }
            boolean result = AliSmsService.sendSms(phone, smsNotify.getTemplateCode(),
            String error = AliSmsService.sendSms(phone, smsNotify.getTemplateCode(),
                    templateParam.toJSONString());
            if (result) {
                log.info("短信发送成功: phone={}, template={}", phone, smsNotify.name());
            } else {
                log.warn("短信发送失败: phone={}, template={}", phone, smsNotify.name());
            }
            // 存储短信记录
            Smsrecord record = new Smsrecord();
            record.setPhone(phone);
            record.setContent(content);
            record.setType(Constants.ONE); // 1=订单通知
            record.setStatus(result ? Constants.ONE : Constants.ZERO);
            record.setType(Constants.ONE);
            record.setStatus(error == null ? Constants.ONE : Constants.ZERO);
            if (error != null) {
                record.setRemark(error);
            }
            record.setCreateTime(new Date());
            record.setDeleted(Constants.ZERO);
            smsrecordMapper.insert(record);
@@ -1828,6 +2150,7 @@
                record.setContent(content);
                record.setType(Constants.ONE);
                record.setStatus(Constants.ZERO);
                record.setRemark(e.getMessage());
                record.setCreateTime(new Date());
                record.setDeleted(Constants.ZERO);
                smsrecordMapper.insert(record);
@@ -1921,6 +2244,7 @@
                .select("s1.address", Orders::getDepositShopAddress)
                .select("s2.name", Orders::getTakeShopName)
                .select("s2.address", Orders::getTakeShopAddress)
                .select("s1.link_phone as takeShopLinkPhone")
                .select("s2.link_phone as takeShopLinkPhone")
                .select("c2.other_field as c2OtherField")
                .select("c2.name as goodLevelName")
@@ -2017,8 +2341,12 @@
        }
        try {
            int lastIndex = token.lastIndexOf("_") + 1;
            Integer memberId = Integer.valueOf(token.substring(lastIndex));
            Member member = memberMapper.selectById(memberId);
            Integer driverId = Integer.valueOf(token.substring(lastIndex));
            DriverInfo driverInfo = driverInfoMapper.selectById(driverId);
            if(Objects.isNull(driverInfo)){
                return false;
            }
            Member member = memberMapper.selectById(driverInfo.getMemberId());
            return member != null
                    && !Constants.ONE.equals(member.getDeleted())
                    && !Constants.ONE.equals(member.getStatus())
@@ -2028,4 +2356,50 @@
        }
    }
    @Override
    public void registerJpushAlias(Integer driverId, String jpushAlias) {
        DriverInfo update = new DriverInfo();
        update.setId(driverId);
        update.setJpushAlias(jpushAlias);
        driverInfoMapper.updateById(update);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int initChangeVersions() {
        Date now = new Date();
        // 1. 补全 version_type 为 NULL 的记录
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .set(DriverInfo::getVersionType, Constants.ZERO)
                .isNull(DriverInfo::getVersionType));
        // 2. 查询所有已有变更版本的 relationDriverId
        List<DriverInfo> changeVersions = driverInfoMapper.selectList(new QueryWrapper<DriverInfo>().lambda()
                .eq(DriverInfo::getVersionType, Constants.ONE)
                .eq(DriverInfo::getDeleted, Constants.ZERO)
                .ne(DriverInfo::getAuditStatus,99)
                .select(DriverInfo::getRelationDriverId)
                .isNotNull(DriverInfo::getRelationDriverId));
        Set<Integer> existingRelationIds = changeVersions.stream()
                .map(DriverInfo::getRelationDriverId)
                .collect(Collectors.toSet());
        // 3. 查询所有没有变更版本的正式版本司机
        QueryWrapper<DriverInfo> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(DriverInfo::getVersionType, Constants.ZERO)
                .eq(DriverInfo::getDeleted, Constants.ZERO);
        List<DriverInfo> officialList = driverInfoMapper.selectList(qw);
        int count = 0;
        for (DriverInfo official : officialList) {
            if (existingRelationIds.contains(official.getId())) {
                continue;
            }
            createDriverChangeVersion(official, official.getId(), now);
            count++;
        }
        return count;
    }
}