package com.doumee.service.business.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.doumee.core.constants.Constants;
|
import com.doumee.core.constants.ResponseStatus;
|
import com.doumee.core.exception.BusinessException;
|
import com.doumee.core.model.PageData;
|
import com.doumee.core.model.PageWrap;
|
import com.doumee.config.jwt.JwtTokenUtil;
|
import com.doumee.core.utils.Secure;
|
import com.doumee.core.utils.Utils;
|
import com.doumee.dao.business.DriverInfoMapper;
|
import com.doumee.dao.business.MemberMapper;
|
import com.doumee.dao.business.MultifileMapper;
|
import com.doumee.dao.business.SmsrecordMapper;
|
import com.doumee.dao.business.CategoryMapper;
|
import com.doumee.dao.business.OrdersMapper;
|
import com.doumee.dao.business.OrdersDetailMapper;
|
import com.doumee.dao.business.RevenueMapper;
|
import com.doumee.biz.system.SystemDictDataBiz;
|
import com.doumee.dao.business.model.Category;
|
import com.doumee.dao.business.model.DriverInfo;
|
import com.doumee.dao.business.model.Member;
|
import com.doumee.dao.business.model.Multifile;
|
import com.doumee.dao.business.model.Smsrecord;
|
import com.doumee.dao.business.model.Orders;
|
import com.doumee.dao.business.model.OrdersDetail;
|
import com.doumee.dao.business.model.Revenue;
|
import com.doumee.dao.vo.AccountResponse;
|
import com.doumee.dao.vo.DriverCenterVO;
|
import com.doumee.dao.vo.DriverGrabOrderVO;
|
import com.doumee.dao.vo.DriverOrderDetailVO;
|
import com.doumee.dao.dto.AuditDTO;
|
import com.doumee.dao.dto.ChangeStatusDTO;
|
import com.doumee.dao.dto.DriverLoginRequest;
|
import com.doumee.dao.dto.DriverRegisterRequest;
|
import com.doumee.dao.dto.DriverVerifyRequest;
|
import com.doumee.dao.dto.DriverActiveOrderDTO;
|
import com.doumee.dao.dto.DriverGrabOrderDTO;
|
import com.doumee.core.utils.aliyun.AliSmsService;
|
import com.doumee.service.business.DriverInfoService;
|
import com.alibaba.fastjson.JSONObject;
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.CollectionUtils;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* 司机注册信息Service实现
|
* @author rk
|
* @date 2026/04/08
|
*/
|
@Service
|
public class DriverInfoServiceImpl implements DriverInfoService {
|
|
@Autowired
|
private DriverInfoMapper driverInfoMapper;
|
|
@Autowired
|
private MemberMapper memberMapper;
|
|
@Autowired
|
private SmsrecordMapper smsrecordMapper;
|
|
@Autowired
|
private JwtTokenUtil jwtTokenUtil;
|
|
@Autowired
|
private Secure secure;
|
|
@Autowired
|
private RedisTemplate<String, Object> redisTemplate;
|
|
@Autowired
|
private MultifileMapper multifileMapper;
|
|
@Autowired
|
private CategoryMapper categoryMapper;
|
|
@Autowired
|
private OrdersMapper ordersMapper;
|
|
@Autowired
|
private RevenueMapper revenueMapper;
|
|
@Autowired
|
private OrdersDetailMapper ordersDetailMapper;
|
|
@Autowired
|
private SystemDictDataBiz systemDictDataBiz;
|
|
@Override
|
public Integer create(DriverInfo driverInfo) {
|
driverInfoMapper.insert(driverInfo);
|
return driverInfo.getId();
|
}
|
|
@Override
|
public void deleteById(Integer id) {
|
driverInfoMapper.deleteById(id);
|
}
|
|
@Override
|
public void delete(DriverInfo driverInfo) {
|
UpdateWrapper<DriverInfo> deleteWrapper = new UpdateWrapper<>(driverInfo);
|
driverInfoMapper.delete(deleteWrapper);
|
}
|
|
@Override
|
public void deleteByIdInBatch(List<Integer> ids) {
|
if (CollectionUtils.isEmpty(ids)) {
|
return;
|
}
|
driverInfoMapper.deleteBatchIds(ids);
|
}
|
|
@Override
|
public void updateById(DriverInfo driverInfo) {
|
driverInfoMapper.updateById(driverInfo);
|
}
|
|
@Override
|
public void updateByIdInBatch(List<DriverInfo> driverInfos) {
|
if (CollectionUtils.isEmpty(driverInfos)) {
|
return;
|
}
|
for (DriverInfo driverInfo : driverInfos) {
|
this.updateById(driverInfo);
|
}
|
}
|
|
@Override
|
public DriverInfo findById(Integer id) {
|
DriverInfo driverInfo = driverInfoMapper.selectById(id);
|
if (Objects.isNull(driverInfo)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
return driverInfo;
|
}
|
|
@Override
|
public DriverInfo findOne(DriverInfo driverInfo) {
|
QueryWrapper<DriverInfo> wrapper = new QueryWrapper<>(driverInfo);
|
return driverInfoMapper.selectOne(wrapper);
|
}
|
|
@Override
|
public List<DriverInfo> findList(DriverInfo driverInfo) {
|
QueryWrapper<DriverInfo> wrapper = new QueryWrapper<>(driverInfo);
|
return driverInfoMapper.selectList(wrapper);
|
}
|
|
@Override
|
public PageData<DriverInfo> findPage(PageWrap<DriverInfo> pageWrap) {
|
IPage<DriverInfo> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
|
MPJLambdaWrapper<DriverInfo> queryWrapper = new MPJLambdaWrapper<>();
|
Utils.MP.blankToNull(pageWrap.getModel());
|
pageWrap.getModel().setDeleted(Constants.ZERO);
|
|
// 司机姓名/手机号(关键字模糊查询)
|
if (StringUtils.isNotBlank(pageWrap.getModel().getKeyword())) {
|
queryWrapper.and(w -> w
|
.like(DriverInfo::getName, pageWrap.getModel().getKeyword())
|
.or()
|
.like(DriverInfo::getTelephone, pageWrap.getModel().getKeyword()));
|
}
|
// 车牌号
|
if (StringUtils.isNotBlank(pageWrap.getModel().getCarCode())) {
|
queryWrapper.like(DriverInfo::getCarCode, pageWrap.getModel().getCarCode());
|
}
|
// 状态
|
if (pageWrap.getModel().getStatus() != null) {
|
queryWrapper.eq(DriverInfo::getStatus, pageWrap.getModel().getStatus());
|
}
|
// 审批状态
|
if (pageWrap.getModel().getAuditStatus() != null) {
|
queryWrapper.eq(DriverInfo::getAuditStatus, pageWrap.getModel().getAuditStatus());
|
}
|
// 创建日期范围
|
if (pageWrap.getModel().getCreateTimeStart() != null) {
|
queryWrapper.ge(DriverInfo::getCreateTime, Utils.Date.getStart(pageWrap.getModel().getCreateTimeStart()));
|
}
|
if (pageWrap.getModel().getCreateTimeEnd() != null) {
|
queryWrapper.le(DriverInfo::getCreateTime, Utils.Date.getEnd(pageWrap.getModel().getCreateTimeEnd()));
|
}
|
// 子查询:余额
|
queryWrapper.selectAll(DriverInfo.class)
|
.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());
|
}
|
}
|
PageData<DriverInfo> pageData = PageData.from(driverInfoMapper.selectPage(page, queryWrapper));
|
for (DriverInfo d : pageData.getRecords()) {
|
d.setGender(Constants.getGenderByIdCard(d.getIdcard()));
|
}
|
return pageData;
|
}
|
|
@Override
|
public long count(DriverInfo driverInfo) {
|
QueryWrapper<DriverInfo> wrapper = new QueryWrapper<>(driverInfo);
|
return driverInfoMapper.selectCount(wrapper);
|
}
|
|
/***************司机验证码登录业务*************/
|
|
@Override
|
public void sendRegisterCode(String telephone) {
|
if (StringUtils.isBlank(telephone)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
// 生成6位数字验证码
|
String code = RandomStringUtils.randomNumeric(6);
|
// 发送短信
|
String templateParam = "{\"code\":\"" + code + "\"}";
|
AliSmsService.sendSms(telephone, "SMS_491325122", templateParam);
|
// 保存短信记录
|
Smsrecord smsrecord = new Smsrecord();
|
smsrecord.setDeleted(Constants.ZERO);
|
smsrecord.setCreateTime(new Date());
|
smsrecord.setUpdateTime(new Date());
|
smsrecord.setPhone(telephone);
|
smsrecord.setContent("司机验证码登录:" + code);
|
smsrecord.setType(Constants.ZERO);
|
smsrecord.setCode(code);
|
smsrecord.setStatus(Constants.ZERO);
|
// 有效期15分钟
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(new Date());
|
calendar.add(Calendar.MINUTE, 15);
|
smsrecord.setValidDate(calendar.getTime());
|
smsrecordMapper.insert(smsrecord);
|
}
|
|
@Override
|
@Transactional
|
public AccountResponse register(DriverRegisterRequest request) {
|
String telephone = request.getTelephone();
|
String code = request.getCode();
|
if (StringUtils.isAnyBlank(telephone, code)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
// 1. 验证短信验证码
|
QueryWrapper<Smsrecord> smsWrapper = new QueryWrapper<>();
|
smsWrapper.lambda().eq(Smsrecord::getPhone, telephone)
|
.eq(Smsrecord::getCode, code)
|
.eq(Smsrecord::getType, Constants.ZERO)
|
.eq(Smsrecord::getStatus, Constants.ZERO)
|
.ge(Smsrecord::getValidDate, new Date())
|
.orderByDesc(Smsrecord::getCreateTime)
|
.last("limit 1");
|
Smsrecord smsrecord = smsrecordMapper.selectOne(smsWrapper);
|
if (Objects.isNull(smsrecord)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "验证码错误或已过期");
|
}
|
// 标记验证码已使用
|
smsrecord.setStatus(Constants.ONE);
|
smsrecord.setUpdateTime(new Date());
|
smsrecordMapper.updateById(smsrecord);
|
|
// 2. 查询是否已有司机账号
|
Member existMember = memberMapper.selectOne(new QueryWrapper<Member>().lambda()
|
.eq(Member::getTelephone, telephone)
|
.eq(Member::getUserType, Constants.ONE)
|
.ne(Member::getStatus, Constants.TWO)
|
.last("limit 1"));
|
|
Date now = new Date();
|
Member member;
|
|
if (Objects.nonNull(existMember)) {
|
// 已有司机账号,直接登录
|
if (!Constants.equalsInteger(existMember.getStatus(), Constants.ZERO)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "账号已停用,请联系管理员");
|
}
|
// 更新登录信息
|
memberMapper.update(new UpdateWrapper<Member>().lambda()
|
.set(Member::getLoginTime, now)
|
.setSql("login_times = login_times + 1")
|
.eq(Member::getId, existMember.getId()));
|
// 更新内存中的登录信息
|
existMember.setLoginTime(now);
|
existMember.setLoginTimes(existMember.getLoginTimes() + 1);
|
member = existMember;
|
} else {
|
// 没有司机账号,注册新用户,默认密码为手机号后六位
|
String salt = RandomStringUtils.randomAlphanumeric(6);
|
String defaultPassword = telephone.substring(telephone.length() - 6);
|
member = new Member();
|
member.setDeleted(Constants.ZERO);
|
member.setCreateTime(now);
|
member.setUpdateTime(now);
|
member.setTelephone(telephone);
|
member.setNickName(telephone.substring(0, 3) + "****" + telephone.substring(7));
|
member.setName(telephone);
|
member.setUserType(Constants.ONE);
|
member.setBusinessStatus(Constants.ZERO);
|
member.setPassword(secure.encryptPassword(defaultPassword, salt));
|
member.setSalt(salt);
|
member.setAmount(Constants.ZERO.longValue());
|
member.setTotalAmount(Constants.ZERO.longValue());
|
member.setStatus(Constants.ZERO);
|
member.setLoginTime(now);
|
member.setLoginTimes(Constants.ONE.longValue());
|
member.setReceiveNum(Constants.ZERO.longValue());
|
member.setPublishNum(Constants.ZERO.longValue());
|
member.setAutoReceiveStatus(Constants.ONE);
|
member.setUseIdentity(Constants.ZERO);
|
memberMapper.insert(member);
|
|
// 创建司机基础信息
|
DriverInfo driverInfo = new DriverInfo();
|
driverInfo.setDeleted(Constants.ZERO);
|
driverInfo.setCreateTime(now);
|
driverInfo.setUpdateTime(now);
|
driverInfo.setTelephone(telephone);
|
driverInfo.setMemberId(member.getId());
|
driverInfo.setStatus(Constants.ZERO);
|
driverInfo.setAuditStatus(null);
|
driverInfoMapper.insert(driverInfo);
|
}
|
|
// 3. 生成token返回
|
AccountResponse accountResponse = new AccountResponse();
|
accountResponse.setToken(JwtTokenUtil.generateTokenForRedis(member.getId(), Constants.ONE, JSONObject.toJSONString(member), redisTemplate));
|
accountResponse.setMember(member);
|
return accountResponse;
|
}
|
|
@Override
|
public AccountResponse login(DriverLoginRequest request) {
|
String telephone = request.getTelephone();
|
String password = request.getPassword();
|
if (StringUtils.isAnyBlank(telephone, password)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
// 查询司机会员
|
Member member = memberMapper.selectOne(new QueryWrapper<Member>().lambda()
|
.eq(Member::getTelephone, telephone)
|
.eq(Member::getUserType, Constants.ONE)
|
.ne(Member::getStatus, Constants.TWO)
|
.last("limit 1"));
|
if (Objects.isNull(member)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "账号不存在");
|
}
|
if (!Constants.equalsInteger(member.getStatus(), Constants.ZERO)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "账号已停用,请联系管理员");
|
}
|
// 校验密码
|
String encryptPwd = secure.encryptPassword(password, member.getSalt());
|
if (!encryptPwd.equals(member.getPassword())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "密码错误");
|
}
|
// 更新登录信息
|
memberMapper.update(new UpdateWrapper<Member>().lambda()
|
.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.setMember(member);
|
return accountResponse;
|
}
|
|
/***************司机实名认证业务*************/
|
|
@Override
|
@Transactional
|
public void submitVerify(Integer memberId, DriverVerifyRequest request) {
|
// 参数基础校验
|
if (StringUtils.isAnyBlank(request.getName(), request.getIdcard(), request.getLivePlace(),
|
request.getCarCode(), request.getIdcardImg(), request.getIdcardImgBack())) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
if (request.getMaritalStatus() == null || request.getCarType() == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
// 身份证号格式校验(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)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前状态不允许提交认证");
|
}
|
// 根据车辆类型判断是否需要驾驶证
|
Category category = categoryMapper.selectById(request.getCarType());
|
if (Objects.isNull(category) || !Constants.equalsInteger(category.getType(), Constants.ONE)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "车辆类型不存在");
|
}
|
boolean needLicense = Constants.equalsInteger(Integer.valueOf(category.getOtherField()), Constants.ONE);
|
if (needLicense) {
|
if (request.getCardStartDate() == null || request.getCardEndDate() == null) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "该车辆类型需要填写驾驶证有效期");
|
}
|
if (request.getLicenseImgUrls() == null || request.getLicenseImgUrls().isEmpty()) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "该车辆类型需要上传驾驶证照片");
|
}
|
}
|
// 车辆照片必填
|
if (request.getCarImgUrls() == null || request.getCarImgUrls().isEmpty()) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "请上传车辆照片");
|
}
|
// 照片数量校验
|
if (request.getCarImgUrls().size() > 3) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "车辆照片最多上传3张");
|
}
|
if (request.getLicenseImgUrls() != null && request.getLicenseImgUrls().size() > 3) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "驾驶证照片最多上传3张");
|
}
|
if (request.getOtherImgUrls() != null && request.getOtherImgUrls().size() > 3) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "其他资料照片最多上传3张");
|
}
|
|
// 更新司机信息
|
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::getAuditStatus, Constants.ZERO)
|
.set(DriverInfo::getUpdateTime, now)
|
.set(DriverInfo::getAuditRemark, null)
|
.set(DriverInfo::getAuditTime, null)
|
.eq(DriverInfo::getId, driverInfo.getId()));
|
|
// 删除旧的照片记录
|
multifileMapper.delete(new QueryWrapper<Multifile>().lambda()
|
.eq(Multifile::getObjId, driverInfo.getId())
|
.in(Multifile::getObjType, 6, 7, 8));
|
|
// 保存车辆照片 objType=6
|
saveMultifileList(driverInfo.getId(), 6, request.getCarImgUrls(), now);
|
// 保存驾驶证照片 objType=7
|
if (!CollectionUtils.isEmpty(request.getLicenseImgUrls())) {
|
saveMultifileList(driverInfo.getId(), 7, request.getLicenseImgUrls(), now);
|
}
|
// 保存其他资料照片 objType=8
|
if (!CollectionUtils.isEmpty(request.getOtherImgUrls())) {
|
saveMultifileList(driverInfo.getId(), 8, request.getOtherImgUrls(), now);
|
}
|
|
// 更新会员司机认证状态为认证中
|
memberMapper.update(new UpdateWrapper<Member>().lambda()
|
.set(Member::getBusinessStatus, Constants.ONE)
|
.set(Member::getUpdateTime, now)
|
.eq(Member::getId, memberId));
|
}
|
|
@Override
|
public DriverInfo getVerifyDetail(Integer memberId) {
|
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);
|
}
|
// 查询车辆类型名称和是否需要驾驶证
|
if (driverInfo.getCarType() != null) {
|
Category category = categoryMapper.selectById(driverInfo.getCarType());
|
if (Objects.nonNull(category)) {
|
driverInfo.setCarTypeName(category.getName());
|
driverInfo.setNeedLicense(Constants.equalsInteger(Integer.valueOf(category.getOtherField()), Constants.ONE) ? Constants.ONE : Constants.ZERO);
|
}
|
}
|
// 查询照片列表
|
List<Multifile> multifileList = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
|
.eq(Multifile::getObjId, driverInfo.getId())
|
.in(Multifile::getObjType, 6, 7, 8)
|
.orderByAsc(Multifile::getSortnum));
|
if (!CollectionUtils.isEmpty(multifileList)) {
|
for (Multifile mf : multifileList) {
|
if (Constants.equalsInteger(mf.getObjType(), 6)) {
|
driverInfo.getCarImgList().add(mf);
|
} else if (Constants.equalsInteger(mf.getObjType(), 7)) {
|
driverInfo.getLicenseImgList().add(mf);
|
} else if (Constants.equalsInteger(mf.getObjType(), 8)) {
|
driverInfo.getOtherImgList().add(mf);
|
}
|
}
|
}
|
return driverInfo;
|
}
|
|
@Override
|
@Transactional
|
public void auditVerify(AuditDTO auditDTO) {
|
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)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
// 只有审批状态为0(待审批)且已填写认证信息才能审批
|
if (!Constants.equalsInteger(driverInfo.getAuditStatus(), Constants.ZERO)
|
|| StringUtils.isBlank(driverInfo.getIdcard())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "当前状态不允许审批");
|
}
|
Date now = new Date();
|
// 审批结果:auditDTO.auditStatus 0=通过→auditStatus=1,1=拒绝→auditStatus=2
|
Integer newAuditStatus;
|
if (Constants.equalsInteger(auditDTO.getAuditStatus(), Constants.ZERO)) {
|
newAuditStatus = Constants.ONE; // 审批通过
|
// 审批通过时司机定级为必填
|
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; // 审批驳回
|
} 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()));
|
}
|
|
@Override
|
public DriverInfo getDetail(Integer id) {
|
DriverInfo driverInfo = driverInfoMapper.selectById(id);
|
if (Objects.isNull(driverInfo) || Constants.equalsInteger(driverInfo.getDeleted(), Constants.ONE)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
// 拼接图片前缀
|
String imgPrefix = "";
|
try {
|
imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
|
+ systemDictDataBiz.queryByCode(Constants.OSS, Constants.DRIVER_FILES).getCode();
|
} catch (Exception e) {
|
// 未配置时忽略
|
}
|
driverInfo.setImgPrefix(imgPrefix);
|
driverInfo.setGender(Constants.getGenderByIdCard(driverInfo.getIdcard()));
|
// 查询车辆类型名称和是否需要驾驶证
|
if (driverInfo.getCarType() != null) {
|
Category category = categoryMapper.selectById(driverInfo.getCarType());
|
if (Objects.nonNull(category)) {
|
driverInfo.setCarTypeName(category.getName());
|
driverInfo.setNeedLicense(Constants.equalsInteger(Integer.valueOf(category.getOtherField()), Constants.ONE) ? Constants.ONE : Constants.ZERO);
|
}
|
}
|
// 查询照片列表:objType=6车辆照片、7驾驶证照片、8其他资料照片
|
List<Multifile> multifileList = multifileMapper.selectList(new QueryWrapper<Multifile>().lambda()
|
.eq(Multifile::getObjId, driverInfo.getId())
|
.in(Multifile::getObjType, 6, 7, 8)
|
.orderByAsc(Multifile::getSortnum));
|
if (!CollectionUtils.isEmpty(multifileList)) {
|
for (Multifile mf : multifileList) {
|
mf.setFileurlFull(imgPrefix + mf.getFileurl());
|
if (Constants.equalsInteger(mf.getObjType(), 6)) {
|
driverInfo.getCarImgList().add(mf);
|
} else if (Constants.equalsInteger(mf.getObjType(), 7)) {
|
driverInfo.getLicenseImgList().add(mf);
|
} else if (Constants.equalsInteger(mf.getObjType(), 8)) {
|
driverInfo.getOtherImgList().add(mf);
|
}
|
}
|
}
|
return driverInfo;
|
}
|
|
@Override
|
public void changeStatus(ChangeStatusDTO dto) {
|
if (dto.getId() == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "主键不能为空");
|
}
|
if (dto.getStatus() == null || (dto.getStatus() != 0 && dto.getStatus() != 1)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "状态参数错误,0=启用;1=禁用");
|
}
|
DriverInfo driverInfo = driverInfoMapper.selectById(dto.getId());
|
if (Objects.isNull(driverInfo) || Constants.equalsInteger(driverInfo.getDeleted(), Constants.ONE)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
driverInfo.setStatus(dto.getStatus());
|
driverInfo.setUpdateTime(new Date());
|
driverInfoMapper.updateById(driverInfo);
|
// 联动修改会员状态(member主键与driver_info主键一致)
|
memberMapper.update(new UpdateWrapper<Member>().lambda()
|
.set(Member::getStatus, dto.getStatus())
|
.set(Member::getUpdateTime, new Date())
|
.eq(Member::getId, driverInfo.getId()));
|
}
|
|
/**
|
* 批量保存附件记录
|
*/
|
private void saveMultifileList(Integer objId, Integer objType, List<String> urls, Date now) {
|
int sortNum = 0;
|
for (String url : urls) {
|
Multifile multifile = new Multifile();
|
multifile.setObjId(objId);
|
multifile.setObjType(objType);
|
multifile.setType(Constants.ZERO);
|
multifile.setFileurl(url);
|
multifile.setIsdeleted(Constants.ZERO);
|
multifile.setCreateDate(now);
|
multifile.setSortnum(sortNum++);
|
multifileMapper.insert(multifile);
|
}
|
}
|
|
@Override
|
public void updateAcceptingStatus(Integer memberId, Integer status) {
|
if (!Constants.ZERO.equals(status) && !Constants.ONE.equals(status)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
|
.eq(DriverInfo::getMemberId, memberId)
|
.eq(DriverInfo::getDeleted, Constants.ZERO)
|
.last("limit 1"));
|
if (driver == null) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
|
}
|
driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
|
.set(DriverInfo::getAcceptingStatus, status)
|
.eq(DriverInfo::getId, driver.getId()));
|
}
|
|
@Override
|
public void updateLocation(Integer memberId, 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::getDeleted, Constants.ZERO)
|
.last("limit 1"));
|
if (driver == null) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
|
}
|
driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
|
.set(DriverInfo::getLongitude, longitude)
|
.set(DriverInfo::getLatitude, latitude)
|
.eq(DriverInfo::getId, driver.getId()));
|
}
|
|
@Override
|
public DriverCenterVO getDriverCenterInfo(Integer memberId) {
|
DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
|
.eq(DriverInfo::getMemberId, memberId)
|
.eq(DriverInfo::getDeleted, Constants.ZERO)
|
.last("limit 1"));
|
if (driver == null) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
|
}
|
DriverCenterVO vo = new DriverCenterVO();
|
vo.setName(driver.getName());
|
vo.setImgUrl(driver.getImgurl());
|
vo.setCarCode(driver.getCarCode());
|
vo.setScore(driver.getScore() != null ? driver.getScore().toPlainString() : "0");
|
vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L);
|
|
// 头像全路径
|
if (StringUtils.isNotBlank(driver.getImgurl())) {
|
String imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
|
+ systemDictDataBiz.queryByCode(Constants.OSS, Constants.MEMBER_FILES).getCode();
|
vo.setFullImgUrl(imgPrefix + driver.getImgurl());
|
}
|
|
// 今日预计佣金:revenue表中今天的收入记录金额之和
|
Date now = new Date();
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(now);
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
cal.set(Calendar.MINUTE, 0);
|
cal.set(Calendar.SECOND, 0);
|
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);
|
|
// 今日接单数:今天完成的订单数(acceptDriver=司机主键,状态=已完成)
|
Long todayOrderCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
|
.eq(Orders::getAcceptDriver, driver.getId())
|
.eq(Orders::getDeleted, Constants.ZERO)
|
.ge(Orders::getFinishTime, todayStart));
|
vo.setTodayOrderCount(todayOrderCount.intValue());
|
|
// 待取货(已接单=3)
|
Long waitPickCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
|
.eq(Orders::getAcceptDriver, driver.getId())
|
.eq(Orders::getDeleted, Constants.ZERO)
|
.eq(Orders::getStatus, Constants.OrderStatus.accepted.getStatus()));
|
vo.setWaitPickCount(waitPickCount.intValue());
|
|
// 待配送(派送中=4)
|
Long waitDeliverCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
|
.eq(Orders::getAcceptDriver, driver.getId())
|
.eq(Orders::getDeleted, Constants.ZERO)
|
.eq(Orders::getStatus, Constants.OrderStatus.delivering.getStatus()));
|
vo.setWaitDeliverCount(waitDeliverCount.intValue());
|
|
return vo;
|
}
|
|
@Override
|
public PageData<DriverGrabOrderVO> grabOrderHall(Integer memberId, PageWrap<DriverGrabOrderDTO> pageWrap) {
|
DriverGrabOrderDTO dto = pageWrap.getModel();
|
|
// 1. 获取司机定位
|
DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
|
.eq(DriverInfo::getMemberId, memberId)
|
.eq(DriverInfo::getDeleted, Constants.ZERO)
|
.last("limit 1"));
|
if (driver == null || driver.getLatitude() == null || driver.getLongitude() == null) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "司机位置信息缺失,请先开启定位");
|
}
|
double driverLat = driver.getLatitude();
|
double driverLng = driver.getLongitude();
|
|
// 2. 预查物品等级对应的物品分类ID
|
List<Integer> goodTypeIds = null;
|
if (dto != null && dto.getGradeId() != null) {
|
List<Category> cats = categoryMapper.selectList(new QueryWrapper<Category>().lambda()
|
.eq(Category::getDeleted, Constants.ZERO)
|
.eq(Category::getType, Constants.TWO)
|
.eq(Category::getRelationId, dto.getGradeId()));
|
if (cats.isEmpty()) {
|
return emptyPage(pageWrap);
|
}
|
goodTypeIds = cats.stream().map(Category::getId).collect(Collectors.toList());
|
}
|
|
// 3. Haversine SQL公式:司机到存件门店距离(km),使用Orders自带坐标
|
String depositDist = "(6371 * acos(cos(radians(" + driverLat + ")) * cos(radians(t.DEPOSIT_LGT)) "
|
+ "* cos(radians(t.DEPOSIT_LAT) - radians(" + driverLng + ")) "
|
+ "+ sin(radians(" + driverLat + ")) * sin(radians(t.DEPOSIT_LGT))))";
|
|
// 4. 构造MPJ查询
|
IPage<Orders> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
|
MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<>();
|
wrapper.selectAll(Orders.class)
|
// 存件门店
|
.select("s1.name", Orders::getDepositShopName)
|
.select("s1.address", Orders::getDepositShopAddress)
|
// 取件门店
|
.select("s2.name", Orders::getTakeShopName)
|
.select("s2.address", Orders::getTakeShopAddress)
|
.select("s2.link_phone as takeShopLinkPhone")
|
// 物品等级贵重标识
|
.select("c2.other_field as c2OtherField")
|
// 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")
|
.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");
|
|
// 核心条件
|
wrapper.eq(Orders::getType, Constants.ONE)
|
.eq(Orders::getStatus, Constants.TWO)
|
.eq(Orders::getDeleted, Constants.ZERO);
|
|
// 加急 OR 在配送范围内
|
wrapper.and(w -> w
|
.eq(Orders::getIsUrgent, Constants.ONE)
|
.or()
|
.apply(depositDist + " <= s1.delivery_area"));
|
|
// 用户距离过滤
|
if (dto != null && dto.getDistance() != null && dto.getDistance() > 0) {
|
double maxKm = dto.getDistance() / 1000.0;
|
wrapper.apply(depositDist + " <= {0}", maxKm);
|
}
|
|
// 物品等级过滤
|
if (goodTypeIds != null && !goodTypeIds.isEmpty()) {
|
wrapper.in(Orders::getGoodType, goodTypeIds);
|
}
|
|
// 排序
|
Integer sortType = (dto != null) ? dto.getSortType() : null;
|
if (sortType != null && sortType == Constants.TWO) {
|
wrapper.last("ORDER BY " + depositDist + " ASC");
|
} else {
|
wrapper.orderByDesc(Orders::getCreateTime);
|
}
|
|
IPage<Orders> result = ordersMapper.selectJoinPage(page, Orders.class, wrapper);
|
|
// 5. 批量查询物品明细
|
List<Integer> orderIds = result.getRecords().stream()
|
.map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, List<OrdersDetail>> detailMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OrdersDetail> allDetails = ordersDetailMapper.selectList(
|
new QueryWrapper<OrdersDetail>().lambda()
|
.in(OrdersDetail::getOrderId, orderIds));
|
for (OrdersDetail d : allDetails) {
|
detailMap.computeIfAbsent(d.getOrderId(), k -> new ArrayList<>()).add(d);
|
}
|
}
|
|
// 6. 构建VO(使用共用方法)
|
Date now = new Date();
|
List<DriverGrabOrderVO> voList = new ArrayList<>();
|
for (Orders order : result.getRecords()) {
|
voList.add(buildDriverOrderVO(order, driverLat, driverLng, true, now, detailMap));
|
}
|
|
// 7. 手动分页
|
PageData<DriverGrabOrderVO> pageData = new PageData<>(result.getCurrent(), result.getSize());
|
pageData.setTotal(result.getTotal());
|
pageData.setRecords(voList);
|
return pageData;
|
}
|
|
@Override
|
public List<DriverGrabOrderVO> activeOrders(Integer memberId, DriverActiveOrderDTO dto) {
|
if (dto == null || dto.getStatus() == null ||
|
(!Constants.equalsInteger(dto.getStatus(), Constants.THREE) && !Constants.equalsInteger(dto.getStatus(), Constants.FOUR))) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单状态只能为3(已抢单)或4(派送中)");
|
}
|
|
// 获取司机信息
|
DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
|
.eq(DriverInfo::getMemberId, memberId)
|
.eq(DriverInfo::getDeleted, Constants.ZERO)
|
.last("limit 1"));
|
if (driver == null) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
|
}
|
|
boolean needDepositDist = Constants.equalsInteger(dto.getStatus(), Constants.THREE);
|
Double driverLat = driver.getLatitude();
|
Double driverLng = driver.getLongitude();
|
|
// MPJ查询
|
MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<>();
|
wrapper.selectAll(Orders.class)
|
.select("s1.name", Orders::getDepositShopName)
|
.select("s1.address", Orders::getDepositShopAddress)
|
.select("s2.name", Orders::getTakeShopName)
|
.select("s2.address", Orders::getTakeShopAddress)
|
.select("s2.link_phone as takeShopLinkPhone")
|
.select("c2.other_field as c2OtherField")
|
.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")
|
.eq(Orders::getAcceptDriver, driver.getId())
|
.eq(Orders::getType, Constants.ONE)
|
.eq(Orders::getStatus, dto.getStatus())
|
.eq(Orders::getDeleted, Constants.ZERO)
|
.orderByAsc(Orders::getAcceptTime);
|
|
List<Orders> ordersList = ordersMapper.selectJoinList(Orders.class, wrapper);
|
|
// 批量查物品明细
|
List<Integer> orderIds = ordersList.stream().map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, List<OrdersDetail>> detailMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OrdersDetail> allDetails = ordersDetailMapper.selectList(
|
new QueryWrapper<OrdersDetail>().lambda()
|
.in(OrdersDetail::getOrderId, orderIds));
|
for (OrdersDetail d : allDetails) {
|
detailMap.computeIfAbsent(d.getOrderId(), k -> new ArrayList<>()).add(d);
|
}
|
}
|
|
// 构建VO(使用共用方法)
|
Date now = new Date();
|
List<DriverGrabOrderVO> voList = new ArrayList<>();
|
for (Orders order : ordersList) {
|
voList.add(buildDriverOrderVO(order, driverLat, driverLng, needDepositDist, now, detailMap));
|
}
|
|
return voList;
|
}
|
|
@Override
|
public DriverOrderDetailVO driverOrderDetail(Integer driverId, Integer orderId) {
|
// 查询订单(MPJ JOIN 门店名称+分类,距离计算使用Orders自带坐标)
|
MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<>();
|
wrapper.selectAll(Orders.class)
|
.select("s1.name", Orders::getDepositShopName)
|
.select("s1.address", Orders::getDepositShopAddress)
|
.select("s2.name", Orders::getTakeShopName)
|
.select("s2.address", Orders::getTakeShopAddress)
|
.select("s2.link_phone as takeShopLinkPhone")
|
.select("c2.other_field as c2OtherField")
|
.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")
|
.eq(Orders::getId, orderId)
|
.eq(Orders::getDeleted, Constants.ZERO);
|
Orders order = ordersMapper.selectJoinOne(Orders.class, wrapper);
|
if (order == null) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
|
}
|
|
// 权限校验:抢单大厅可见(status=2, type=1) 或 已抢单/派送中(acceptDriver=driverId)
|
boolean canView = false;
|
if (Constants.equalsInteger(order.getStatus(), Constants.TWO) && Constants.equalsInteger(order.getType(), Constants.ONE)) {
|
canView = true;
|
}
|
if (driverId != null && driverId.equals(order.getAcceptDriver())) {
|
canView = true;
|
}
|
if (!canView) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权查看该订单");
|
}
|
|
// 获取司机位置(用于距离计算)
|
Double driverLat = null;
|
Double driverLng = null;
|
if (driverId != null) {
|
DriverInfo driver = driverInfoMapper.selectById(driverId);
|
if (driver != null) {
|
driverLat = driver.getLatitude();
|
driverLng = driver.getLongitude();
|
}
|
}
|
|
// 物品明细
|
List<OrdersDetail> details = ordersDetailMapper.selectList(
|
new QueryWrapper<OrdersDetail>().lambda()
|
.eq(OrdersDetail::getOrderId, orderId));
|
Map<Integer, List<OrdersDetail>> detailMap = new HashMap<>();
|
for (OrdersDetail d : details) {
|
detailMap.computeIfAbsent(d.getOrderId(), k -> new ArrayList<>()).add(d);
|
}
|
|
// 使用共用方法构建基础VO字段
|
Date now = new Date();
|
DriverGrabOrderVO base = buildDriverOrderVO(order, driverLat, driverLng, true, now, detailMap);
|
|
// 构建详情VO
|
DriverOrderDetailVO vo = new DriverOrderDetailVO();
|
vo.setId(base.getId());
|
vo.setCode(base.getCode());
|
vo.setRemainMinutes(base.getRemainMinutes());
|
vo.setIsUrgent(base.getIsUrgent());
|
vo.setDepositShopName(base.getDepositShopName());
|
vo.setDepositShopAddress(base.getDepositShopAddress());
|
vo.setDepositDistance(base.getDepositDistance());
|
vo.setTakeName(base.getTakeName());
|
vo.setTakeDistance(base.getTakeDistance());
|
vo.setContactPhone(base.getContactPhone());
|
vo.setDriverFee(base.getDriverFee());
|
vo.setUrgentAmount(base.getUrgentAmount());
|
vo.setIsValuable(base.getIsValuable());
|
|
// 物品明细(转换类型)
|
List<DriverOrderDetailVO.OrderItem> detailItems = new ArrayList<>();
|
if (base.getItems() != null) {
|
for (DriverGrabOrderVO.OrderItem src : base.getItems()) {
|
DriverOrderDetailVO.OrderItem item = new DriverOrderDetailVO.OrderItem();
|
item.setName(src.getName());
|
item.setQuantity(src.getQuantity());
|
detailItems.add(item);
|
}
|
}
|
vo.setItems(detailItems);
|
|
// 详情特有字段
|
vo.setStatus(order.getStatus());
|
vo.setStatusDesc(getStatusDesc(order.getStatus()));
|
|
// 客户信息
|
String customerInfo = "";
|
if (StringUtils.isNotBlank(order.getTakeUser())) {
|
customerInfo = order.getTakeUser();
|
}
|
if (StringUtils.isNotBlank(order.getTakePhone()) && order.getTakePhone().length() >= 4) {
|
customerInfo += "(手机尾号" + order.getTakePhone().substring(order.getTakePhone().length() - 4) + ")";
|
}
|
vo.setCustomerInfo(customerInfo);
|
|
// 导航经纬度(使用Orders自带坐标)
|
if (Constants.equalsInteger(order.getStatus(), Constants.TWO)) {
|
if (order.getDepositLgt() != null && order.getDepositLat() != null) {
|
vo.setNavigateLat(order.getDepositLgt().doubleValue());
|
vo.setNavigateLng(order.getDepositLat().doubleValue());
|
}
|
} else {
|
if (order.getTakeLgt() != null && order.getTakeLat() != null) {
|
vo.setNavigateLat(order.getTakeLgt().doubleValue());
|
vo.setNavigateLng(order.getTakeLat().doubleValue());
|
}
|
}
|
|
// 下单附件图片
|
String imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
|
+ systemDictDataBiz.queryByCode(Constants.OSS, Constants.MEMBER_FILES).getCode();
|
vo.setOrderImages(getFileUrls(orderId, Constants.FileType.ORDER_FILE.getKey(), imgPrefix));
|
|
return vo;
|
}
|
|
private List<String> getFileUrls(Integer orderId, int objType, String prefix) {
|
List<Multifile> files = multifileMapper.selectList(
|
new QueryWrapper<Multifile>().lambda()
|
.eq(Multifile::getObjId, orderId)
|
.eq(Multifile::getObjType, objType)
|
.eq(Multifile::getIsdeleted, Constants.ZERO)
|
.orderByAsc(Multifile::getSortnum));
|
List<String> urls = new ArrayList<>();
|
if (files != null) {
|
for (Multifile f : files) {
|
if (StringUtils.isNotBlank(f.getFileurl())) {
|
urls.add(prefix + f.getFileurl());
|
}
|
}
|
}
|
return urls;
|
}
|
|
private String getStatusDesc(Integer status) {
|
if (status == null) return "";
|
switch (status) {
|
case 0: return "待支付";
|
case 1: return "待寄存";
|
case 2: return "已寄存";
|
case 3: return "已接单";
|
case 4: return "派送中";
|
case 5: return "待取件";
|
case 7: return "已完成";
|
case 96: return "订单关闭";
|
case 98: return "取消中";
|
case 99: return "已取消";
|
default: return "";
|
}
|
}
|
|
private String formatDistance(double km) {
|
if (km < 1) {
|
return Math.round(km * 1000) + "m";
|
}
|
return String.format("%.1fkm", km);
|
}
|
|
private double haversine(double lat1, double lng1, double lat2, double lng2) {
|
double R = 6371;
|
double dLat = Math.toRadians(lat2 - lat1);
|
double dLng = Math.toRadians(lng2 - lng1);
|
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
|
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
|
* Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
return R * c;
|
}
|
|
private <T> PageData<T> emptyPage(PageWrap<?> pageWrap) {
|
PageData<T> pd = new PageData<>(pageWrap.getPage(), pageWrap.getCapacity());
|
pd.setTotal(0);
|
pd.setRecords(new ArrayList<>());
|
return pd;
|
}
|
|
/**
|
* 构建司机端订单列表共用VO(使用Orders自带坐标计算距离)
|
*
|
* @param order 订单实体(MPJ已填充depositShopName等关联字段)
|
* @param driverLat 司机纬度
|
* @param driverLng 司机经度
|
* @param needDepositDist 是否需要计算距存件门店距离
|
* @param now 当前时间
|
* @param detailMap 订单物品明细Map(orderId → detailList)
|
* @return DriverGrabOrderVO
|
*/
|
private DriverGrabOrderVO buildDriverOrderVO(Orders order, Double driverLat, Double driverLng,
|
boolean needDepositDist, Date now, Map<Integer, List<OrdersDetail>> detailMap) {
|
DriverGrabOrderVO vo = new DriverGrabOrderVO();
|
vo.setId(order.getId());
|
vo.setCode(order.getCode());
|
|
// 剩余时长
|
if (order.getEstimatedDeliveryTime() != null) {
|
long diffMs = order.getEstimatedDeliveryTime().getTime() - now.getTime();
|
vo.setRemainMinutes(diffMs > 0 ? diffMs / (60 * 1000) : 0L);
|
} else {
|
vo.setRemainMinutes(0L);
|
}
|
|
vo.setIsUrgent(order.getIsUrgent());
|
vo.setDriverFee(order.getDriverFee());
|
vo.setUrgentAmount(order.getUrgentAmount());
|
|
// 存件门店(使用Orders自带坐标)
|
vo.setDepositShopName(order.getDepositShopName());
|
vo.setDepositShopAddress(order.getDepositShopAddress());
|
if (needDepositDist && driverLat != null && driverLng != null
|
&& order.getDepositLgt() != null && order.getDepositLat() != null) {
|
double distKm = haversine(driverLat, driverLng,
|
order.getDepositLgt().doubleValue(), order.getDepositLat().doubleValue());
|
vo.setDepositDistance(formatDistance(distKm));
|
}
|
|
// 取件信息 + 联系电话(使用Orders自带坐标)
|
boolean hasTakeShop = order.getTakeShopId() != null && StringUtils.isNotBlank(order.getTakeShopName());
|
if (hasTakeShop) {
|
vo.setTakeName(order.getTakeShopName());
|
vo.setContactPhone(order.getTakeShopLinkPhone());
|
} else {
|
vo.setTakeName(order.getTakeLocation());
|
vo.setContactPhone(order.getTakePhone());
|
}
|
if (driverLat != null && driverLng != null
|
&& order.getTakeLgt() != null && order.getTakeLat() != null) {
|
double takeDist = haversine(driverLat, driverLng,
|
order.getTakeLgt().doubleValue(), order.getTakeLat().doubleValue());
|
vo.setTakeDistance(formatDistance(takeDist));
|
}
|
|
// 贵重物品
|
vo.setIsValuable("1".equals(order.getC2OtherField()));
|
|
// 物品明细
|
List<OrdersDetail> details = detailMap.getOrDefault(order.getId(), Collections.emptyList());
|
List<DriverGrabOrderVO.OrderItem> items = new ArrayList<>();
|
for (OrdersDetail detail : details) {
|
DriverGrabOrderVO.OrderItem item = new DriverGrabOrderVO.OrderItem();
|
item.setName(detail.getLuggageName());
|
item.setQuantity(detail.getNum());
|
items.add(item);
|
}
|
vo.setItems(items);
|
|
return vo;
|
}
|
|
}
|