rk
2 天以前 2acc40db4dd14c3d27ea1645f2b5833969e5c1cb
server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -21,27 +21,26 @@
import com.doumee.dao.business.OrdersDetailMapper;
import com.doumee.dao.business.RevenueMapper;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.biz.system.OperationConfigBiz;
import com.doumee.dao.business.OrderLogMapper;
import com.doumee.dao.business.model.Category;
import com.doumee.dao.business.model.DriverInfo;
import com.doumee.dao.business.model.OrderLog;
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.dto.*;
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.dao.business.model.Notice;
import com.doumee.service.business.DriverInfoService;
import com.doumee.service.business.NoticeService;
import com.alibaba.fastjson.JSONObject;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.RandomStringUtils;
@@ -98,6 +97,49 @@
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private OrderLogMapper orderLogMapper;
    @Autowired
    private OperationConfigBiz operationConfigBiz;
    @Autowired
    private NoticeService noticeService;
    /**
     * 发送订单站内信通知
     */
    private void sendOrderNotice(Integer memberId, Constants.MemberOrderNotify notify, Integer orderId, String... params) {
        Notice notice = new Notice();
        notice.setUserType(0); // 0=会员
        notice.setUserId(memberId);
        notice.setTitle(notify.getTitle());
        notice.setContent(notify.format(params));
        notice.setObjId(orderId);
        notice.setObjType(0); // 0=订单
        notice.setStatus(0);  // 0=未读
        notice.setIsdeleted(Constants.ZERO);
        notice.setCreateDate(new Date());
        noticeService.create(notice);
    }
    /**
     * 发送门店站内信通知
     */
    private void sendShopNotice(Integer shopId, Constants.ShopOrderNotify notify, Integer orderId, String... params) {
        Notice notice = new Notice();
        notice.setUserType(2); // 2=门店
        notice.setUserId(shopId);
        notice.setTitle(notify.getTitle());
        notice.setContent(notify.format(params));
        notice.setObjId(orderId);
        notice.setObjType(0); // 0=订单
        notice.setStatus(0);  // 0=未读
        notice.setIsdeleted(Constants.ZERO);
        notice.setCreateDate(new Date());
        noticeService.create(notice);
    }
    @Override
    public Integer create(DriverInfo driverInfo) {
@@ -453,7 +495,8 @@
                .set(DriverInfo::getCardEndDate, request.getCardEndDate())
                .set(DriverInfo::getIdcardImg, request.getIdcardImg())
                .set(DriverInfo::getIdcardImgBack, request.getIdcardImgBack())
                .set(DriverInfo::getAuditStatus, Constants.ZERO)
                .set(DriverInfo::getAliAccount, request.getAliAccount())
                .set(DriverInfo::getAliName, request.getAliName())
                .set(DriverInfo::getUpdateTime, now)
                .set(DriverInfo::getAuditRemark, null)
                .set(DriverInfo::getAuditTime, null)
@@ -660,6 +703,9 @@
        if (driver == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        if (!Constants.THREE.equals(driver.getAuditStatus())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "请先完成押金支付");
        }
        driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda()
                .set(DriverInfo::getAcceptingStatus, status)
                .eq(DriverInfo::getId, driver.getId()));
@@ -763,6 +809,10 @@
        if (driver == null || driver.getLatitude() == null || driver.getLongitude() == null) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "司机位置信息缺失,请先开启定位");
        }
        // 校验司机已支付押金
        if (!Constants.THREE.equals(driver.getAuditStatus())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "请先完成押金支付");
        }
        double driverLat = driver.getLatitude();
        double driverLng = driver.getLongitude();
@@ -807,6 +857,11 @@
        wrapper.eq(Orders::getType, Constants.ONE)
                .eq(Orders::getStatus, Constants.TWO)
                .eq(Orders::getDeleted, Constants.ZERO);
        // 司机级别 >= 订单物品级别
        if (driver.getDriverLevel() != null) {
            wrapper.apply("t.GOOD_LEVEL <= {0}", driver.getDriverLevel());
        }
        // 加急 OR 在配送范围内
        wrapper.and(w -> w
@@ -1046,6 +1101,225 @@
        return vo;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Integer driverId, Integer orderId, String reason) {
        // 1. 查询司机信息
        DriverInfo driver = driverInfoMapper.selectById(driverId);
        if (driver == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        // 2. 校验订单
        Orders order = ordersMapper.selectById(orderId);
        if (order == null || Constants.ONE.equals(order.getDeleted())) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
        }
        if (!Constants.ONE.equals(order.getType())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单可取消");
        }
        if (!Constants.TWO.equals(order.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许取消");
        }
        if (!driverId.equals(order.getAcceptDriver())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作该订单");
        }
        // 3. 每日取消次数限制
        String limitStr = operationConfigBiz.getConfig().getDriverDailyCancelLimit();
        int limit = 3;
        if (StringUtils.isNotBlank(limitStr)) {
            try { limit = Integer.parseInt(limitStr); } catch (NumberFormatException ignored) {}
        }
        Calendar cal = Calendar.getInstance();
        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();
        Long todayCancelCount = orderLogMapper.selectCount(new QueryWrapper<OrderLog>().lambda()
                .eq(OrderLog::getOptUserId, driver.getMemberId())
                .eq(OrderLog::getObjType, Constants.ORDER_LOG_CANCEL)
                .eq(OrderLog::getOptUserType, Constants.ONE)
                .ge(OrderLog::getCreateTime, todayStart));
        if (todayCancelCount != null && todayCancelCount >= limit) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "今日取消次数已达上限");
        }
        // 4. 重置订单司机字段(保持status=2,释放回抢单大厅)
        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getAcceptDriver, null)
                .set(Orders::getAcceptTime, null)
                .set(Orders::getAcceptType, null)
                .eq(Orders::getId, orderId));
        // 5. 写入取消日志
        OrderLog log = new OrderLog();
        log.setOrderId(orderId);
        log.setTitle("司机取消订单");
        log.setLogInfo(StringUtils.isNotBlank(reason) ? reason : "司机取消接单");
        log.setObjType(Constants.ORDER_LOG_CANCEL);
        log.setOptUserId(driver.getMemberId());
        log.setOptUserType(Constants.ONE);
        log.setOrderStatus(order.getStatus());
        log.setCreateTime(new Date());
        log.setDeleted(Constants.ZERO);
        orderLogMapper.insert(log);
        // 通知会员:司机变更
        sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.DRIVER_CHANGED, orderId,
                "orderNo", order.getCode());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void grabOrder(Integer driverId, Integer orderId) {
        // 1. 校验司机
        DriverInfo driver = driverInfoMapper.selectById(driverId);
        if (driver == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        // 2. 校验司机接单状态
        if (!Constants.ONE.equals(driver.getAcceptingStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先开启接单状态");
        }
        if (!Integer.valueOf(3).equals(driver.getAuditStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "司机审核未通过或未缴纳押金");
        }
        if (driver.getDriverLevel() == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "司机等级未设置");
        }
        // 3. 校验订单
        Orders order = ordersMapper.selectById(orderId);
        if (order == null || Constants.ONE.equals(order.getDeleted())) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
        }
        if (!Constants.ONE.equals(order.getType())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单可抢单");
        }
        if (!Constants.TWO.equals(order.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许抢单");
        }
        // 4. 校验司机等级 ≥ 订单等级
        if (order.getGoodLevel() != null && driver.getDriverLevel() < order.getGoodLevel()) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "司机等级不足,无法抢该订单");
        }
        // 5. 原子更新:带 status=2 条件防止并发重复抢单
        Date now = new Date();
        int rows = ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getAcceptDriver, driverId)
                .set(Orders::getAcceptTime, now)
                .set(Orders::getAcceptType, 0) // 0=手动抢单
                .set(Orders::getStatus, Constants.OrderStatus.accepted.getStatus())
                .set(Orders::getUpdateTime, now)
                .eq(Orders::getId, orderId)
                .eq(Orders::getStatus, Constants.TWO));
        if (rows == 0) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "抢单失败,订单已被抢或状态已变更");
        }
        // 6. 写入操作日志
        OrderLog log = new OrderLog();
        log.setOrderId(orderId);
        log.setTitle("司机抢单");
        log.setLogInfo("司机【" + driver.getName() + "】抢单成功");
        log.setObjType(Constants.ORDER_LOG_DRIVER_PICKUP);
        log.setOptUserId(driver.getMemberId());
        log.setOptUserType(Constants.ONE);
        log.setOrderStatus(Constants.OrderStatus.accepted.getStatus());
        log.setCreateTime(now);
        log.setDeleted(Constants.ZERO);
        orderLogMapper.insert(log);
        // 7. 通知会员:司机已抢单
        sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_GRABBED, orderId,
                "driverName", driver.getName());
        // 通知存件门店:订单已抢单待取件
        if (order.getDepositShopId() != null) {
            sendShopNotice(order.getDepositShopId(), Constants.ShopOrderNotify.WAIT_PICKUP, orderId,
                    "orderNo", order.getCode());
        }
    }
    @Override
    @Transactional
    public void confirmPickup(Integer driverId, DriverPickupDTO dto) {
        Integer orderId = dto.getOrderId();
        // 1. 校验司机
        DriverInfo driver = driverInfoMapper.selectById(driverId);
        if (driver == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        // 2. 校验订单
        Orders order = ordersMapper.selectById(orderId);
        if (order == null || Constants.ONE.equals(order.getDeleted())) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
        }
        if (!Constants.ONE.equals(order.getType())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单支持此操作");
        }
        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.accepted.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许取件确认");
        }
        if (!driverId.equals(order.getAcceptDriver())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作该订单");
        }
        // 3. 保存取件图片
        Date now = new Date();
        if (dto.getImages() != null && !dto.getImages().isEmpty()) {
            int sortNum = 0;
            for (String url : dto.getImages()) {
                Multifile multifile = new Multifile();
                multifile.setObjId(orderId);
                multifile.setObjType(Constants.FileType.DRIVER_TAKE.getKey());
                multifile.setType(Constants.ZERO);
                multifile.setFileurl(url);
                multifile.setIsdeleted(Constants.ZERO);
                multifile.setCreateDate(now);
                multifile.setSortnum(sortNum++);
                multifileMapper.insert(multifile);
            }
        }
        // 4. 更新订单状态为派送中(4)
        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
                .set(Orders::getStatus, Constants.OrderStatus.delivering.getStatus())
                .set(Orders::getUpdateTime, now)
                .eq(Orders::getId, orderId));
        // 5. 写入操作日志
        OrderLog log = new OrderLog();
        log.setOrderId(orderId);
        log.setTitle("司机完成取件");
        log.setLogInfo("司机【" + driver.getName() + "】完成取件,开始派送");
        log.setObjType(Constants.ORDER_LOG_DRIVER_PICKUP);
        log.setOptUserId(driver.getMemberId());
        log.setOptUserType(Constants.ONE);
        log.setOrderStatus(Constants.OrderStatus.delivering.getStatus());
        log.setCreateTime(now);
        log.setDeleted(Constants.ZERO);
        orderLogMapper.insert(log);
        // 通知会员:订单配送中
        sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.DELIVERING, orderId,
                "orderNo", order.getCode(),
                "driverName", driver.getName());
        // 通知取件门店:订单配送中
        if (order.getTakeShopId() != null) {
            sendShopNotice(order.getTakeShopId(), Constants.ShopOrderNotify.DELIVERING, orderId,
                    "orderNo", order.getCode(),
                    "driverName", driver.getName());
        }
    }
    private List<String> getFileUrls(Integer orderId, int objType, String prefix) {
        List<Multifile> files = multifileMapper.selectList(
                new QueryWrapper<Multifile>().lambda()