From 467fe3b3ec6aa9d449b094bdd9df4611323d88d1 Mon Sep 17 00:00:00 2001
From: rk <94314517@qq.com>
Date: 星期五, 24 四月 2026 21:43:50 +0800
Subject: [PATCH] 代码生成

---
 server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java |  683 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 663 insertions(+), 20 deletions(-)

diff --git a/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java b/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
index 5c292e9..5bd7f52 100644
--- a/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
+++ b/server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -4,6 +4,7 @@
 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.biz.system.impl.AreasBizImpl;
 import com.doumee.core.constants.Constants;
 import com.doumee.core.constants.ResponseStatus;
 import com.doumee.core.exception.BusinessException;
@@ -15,35 +16,29 @@
 import com.doumee.dao.business.DriverInfoMapper;
 import com.doumee.dao.business.MemberMapper;
 import com.doumee.dao.business.MultifileMapper;
+import com.doumee.dao.business.OrderCommentMapper;
 import com.doumee.dao.business.SmsrecordMapper;
 import com.doumee.dao.business.CategoryMapper;
 import com.doumee.dao.business.OrdersMapper;
+import com.doumee.dao.business.ShopInfoMapper;
 import com.doumee.dao.business.OrdersDetailMapper;
 import com.doumee.dao.business.RevenueMapper;
+import com.doumee.dao.business.model.*;
+import com.doumee.service.business.AreasService;
 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.biz.system.OperationConfigBiz;
+import com.doumee.dao.business.OrderLogMapper;
+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.service.business.DriverInfoService;
+import com.doumee.service.business.NoticeService;
 import com.alibaba.fastjson.JSONObject;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -60,6 +55,7 @@
  * @author rk
  * @date 2026/04/08
  */
+@Slf4j
 @Service
 public class DriverInfoServiceImpl implements DriverInfoService {
 
@@ -91,6 +87,12 @@
     private OrdersMapper ordersMapper;
 
     @Autowired
+    private ShopInfoMapper shopInfoMapper;
+
+    @Autowired
+    private OrderCommentMapper orderCommentMapper;
+
+    @Autowired
     private RevenueMapper revenueMapper;
 
     @Autowired
@@ -98,6 +100,73 @@
 
     @Autowired
     private SystemDictDataBiz systemDictDataBiz;
+
+    @Autowired
+    private OrderLogMapper orderLogMapper;
+
+    @Autowired
+    private OperationConfigBiz operationConfigBiz;
+
+    @Autowired
+    private NoticeService noticeService;
+
+    @Autowired
+    private AreasBizImpl areasBiz;
+
+    /**
+     * 鍙戦�佽鍗曠珯鍐呬俊閫氱煡
+     */
+    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);
+    }
+
+    /**
+     * 鍙戦�佸徃鏈虹珯鍐呬俊閫氱煡
+     */
+    private void sendDriverNotice(Integer driverId, Constants.DriverOrderNotify notify, Integer orderId, String... params) {
+        DriverInfo driver = driverInfoMapper.selectById(driverId);
+        if (driver == null || driver.getMemberId() == null) {
+            return;
+        }
+        Notice notice = new Notice();
+        notice.setUserType(1); // 1=鍙告満
+        notice.setUserId(driver.getMemberId());
+        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) {
@@ -308,7 +377,7 @@
             member.setUpdateTime(now);
             member.setTelephone(telephone);
             member.setNickName(telephone.substring(0, 3) + "****" + telephone.substring(7));
-            member.setName(telephone);
+            member.setName(member.getNickName());
             member.setUserType(Constants.ONE);
             member.setBusinessStatus(Constants.ZERO);
             member.setPassword(secure.encryptPassword(defaultPassword, salt));
@@ -326,13 +395,15 @@
 
             // 鍒涘缓鍙告満鍩虹淇℃伅
             DriverInfo driverInfo = new DriverInfo();
+            driverInfo.setId(member.getId());
             driverInfo.setDeleted(Constants.ZERO);
             driverInfo.setCreateTime(now);
             driverInfo.setUpdateTime(now);
             driverInfo.setTelephone(telephone);
+            driverInfo.setName(member.getNickName());
             driverInfo.setMemberId(member.getId());
             driverInfo.setStatus(Constants.ZERO);
-            driverInfo.setAuditStatus(null);
+            driverInfo.setAuditStatus(99);
             driverInfoMapper.insert(driverInfo);
         }
 
@@ -453,8 +524,10 @@
                 .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::getAuditStatus, Constants.ZERO)
                 .set(DriverInfo::getAuditRemark, null)
                 .set(DriverInfo::getAuditTime, null)
                 .eq(DriverInfo::getId, driverInfo.getId()));
@@ -485,18 +558,39 @@
     @Override
     public DriverInfo getVerifyDetail(Integer memberId) {
         DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
-                .eq(DriverInfo::getMemberId, memberId)
+                .eq(DriverInfo::getId, memberId)
                 .eq(DriverInfo::getDeleted, Constants.ZERO)
                 .last("limit 1"));
         if (Objects.isNull(driverInfo)) {
             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);
         // 鏌ヨ杞﹁締绫诲瀷鍚嶇О鍜屾槸鍚﹂渶瑕侀┚椹惰瘉
         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);
+            }
+        }
+        // 鏌ヨ鐪佸競鍖轰俊鎭�
+        if (driverInfo.getAreaId() != null) {
+            Areas district = areasBiz.resolveArea(driverInfo.getAreaId());
+            if (district != null) {
+                driverInfo.setDistrictId(district.getId());
+                driverInfo.setDistrictName(district.getName());
+                driverInfo.setCityId(district.getCityId());
+                driverInfo.setCityName(district.getCityName());
+                driverInfo.setProvinceId(district.getProvinceId());
+                driverInfo.setProvinceName(district.getProvinceName());
             }
         }
         // 鏌ヨ鐓х墖鍒楄〃
@@ -562,6 +656,20 @@
                 .set(Member::getBusinessStatus, driverStatus)
                 .set(Member::getUpdateTime, now)
                 .eq(Member::getId, driverInfo.getMemberId()));
+
+        // 鐭俊閫氱煡
+        if (Constants.equalsInteger(newAuditStatus, Constants.ONE)) {
+            // 瀹℃壒閫氳繃
+            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() : "");
+        }
     }
 
     @Override
@@ -660,6 +768,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()));
@@ -697,8 +808,11 @@
         vo.setImgUrl(driver.getImgurl());
         vo.setCarCode(driver.getCarCode());
         vo.setScore(driver.getScore() != null ? driver.getScore().toPlainString() : "0");
+        vo.setDriverLevel(driver.getDriverLevel());
+        vo.setAuditStatus(driver.getAuditStatus());
+        vo.setAuditRemark(driver.getAuditRemark());
         vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L);
-
+        vo.setAcceptingStatus(driver.getAcceptingStatus());
         // 澶村儚鍏ㄨ矾寰�
         if (StringUtils.isNotBlank(driver.getImgurl())) {
             String imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
@@ -752,6 +866,54 @@
     }
 
     @Override
+    public com.doumee.dao.vo.DriverStatsVO getDriverStats(Integer memberId) {
+        DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda()
+                .eq(DriverInfo::getId, memberId)
+                .eq(DriverInfo::getDeleted, Constants.ZERO)
+                .last("limit 1"));
+        if (driver == null) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "鍙告満淇℃伅涓嶅瓨鍦�");
+        }
+
+        com.doumee.dao.vo.DriverStatsVO vo = new com.doumee.dao.vo.DriverStatsVO();
+
+        // 绱浣i噾锛歵ype=0(瀹屾垚璁㈠崟) + vaildStatus=1(宸插叆璐�)
+        QueryWrapper<Revenue> totalWrapper = new QueryWrapper<>();
+        totalWrapper.lambda()
+                .eq(Revenue::getMemberId, memberId)
+                .eq(Revenue::getMemberType, Constants.ONE)
+                .eq(Revenue::getType, Constants.ZERO)
+                .eq(Revenue::getVaildStatus, Constants.ONE)
+                .eq(Revenue::getDeleted, Constants.ZERO);
+        totalWrapper.select("IFNULL(SUM(AMOUNT),0) as amount");
+        Revenue totalResult = revenueMapper.selectOne(totalWrapper);
+        vo.setTotalCommission(totalResult != null && totalResult.getAmount() != null ? totalResult.getAmount() : 0L);
+
+        // 寰呯粨绠椾剑閲戯細type=0(瀹屾垚璁㈠崟) + vaildStatus=0(鍏ヨ处涓�)
+        QueryWrapper<Revenue> pendingWrapper = new QueryWrapper<>();
+        pendingWrapper.lambda()
+                .eq(Revenue::getMemberId, memberId)
+                .eq(Revenue::getMemberType, Constants.ONE)
+                .eq(Revenue::getType, Constants.ZERO)
+                .eq(Revenue::getVaildStatus, Constants.ZERO)
+                .eq(Revenue::getDeleted, Constants.ZERO);
+        pendingWrapper.select("IFNULL(SUM(AMOUNT),0) as amount");
+        Revenue pendingResult = revenueMapper.selectOne(pendingWrapper);
+        vo.setPendingCommission(pendingResult != null && pendingResult.getAmount() != null ? pendingResult.getAmount() : 0L);
+
+        // 璁㈠崟鎬绘暟
+        Long totalOrderCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getAcceptDriver, driver.getId())
+                .eq(Orders::getDeleted, Constants.ZERO));
+        vo.setTotalOrderCount(totalOrderCount.intValue());
+
+        // 閽卞寘浣欓
+        vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L);
+
+        return vo;
+    }
+
+    @Override
     public PageData<DriverGrabOrderVO> grabOrderHall(Integer memberId, PageWrap<DriverGrabOrderDTO> pageWrap) {
         DriverGrabOrderDTO dto = pageWrap.getModel();
 
@@ -762,6 +924,10 @@
                 .last("limit 1"));
         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 +973,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
@@ -1038,12 +1209,389 @@
             }
         }
 
+        // 寮傚湴瀵勫瓨瀹炴椂缁忕含搴︼紙鎸夌姸鎬佽繑鍥烇級
+        if (Constants.ONE.equals(order.getType())) {
+            // 鍙告満鑷韩缁忕含搴�
+            vo.setDriverLng(driverLng);
+            vo.setDriverLat(driverLat);
+
+            // status=3(宸叉帴鍗�)锛氳繑鍥炲瓨浠堕棬搴楃粡绾害
+            if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.accepted.getStatus())) {
+                if (order.getDepositShopId() != null) {
+                    ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId());
+                    if (depositShop != null) {
+                        vo.setDepositShopLng(depositShop.getLongitude());
+                        vo.setDepositShopLat(depositShop.getLatitude());
+                    }
+                }
+            }
+            // status=4(閰嶉�佷腑)锛氳繑鍥炲彇浠剁偣缁忕含搴�
+            if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())) {
+                if (order.getTakeShopId() != null) {
+                    ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId());
+                    if (takeShop != null) {
+                        vo.setTakeLng(takeShop.getLongitude());
+                        vo.setTakeLat(takeShop.getLatitude());
+                    }
+                } else if (order.getTakeLgt() != null && order.getTakeLat() != null) {
+                    vo.setTakeLng(order.getTakeLgt().doubleValue());
+                    vo.setTakeLat(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));
 
+        // 璇勪环淇℃伅
+        vo.setCommentStatus(order.getCommentStatus());
+        if (Constants.equalsInteger(order.getCommentStatus(), Constants.ONE)) {
+            vo.setCommentTime(order.getCommentTime());
+            // 鏌ヨ鍙告満璇勪环璁板綍
+            OrderComment driverComment = orderCommentMapper.selectOne(new QueryWrapper<OrderComment>().lambda()
+                    .eq(OrderComment::getOrderId, orderId)
+                    .eq(OrderComment::getTargetType, Constants.THREE)
+                    .eq(OrderComment::getDeleted, Constants.ZERO)
+                    .last("limit 1"));
+            if (driverComment != null) {
+                vo.setDriverScore(driverComment.getScore());
+                vo.setCommentContent(driverComment.getContent());
+            }
+            // 璇勪环闄勪欢鍥剧墖
+            vo.setCommentImages(getFileUrls(orderId, Constants.FileType.COMMENT_ATTACH.getKey(), imgPrefix));
+        }
+
         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.OrderLogType.driverCancel.getStatus())
+                .eq(OrderLog::getOptUserType, Constants.ONE)
+                .ge(OrderLog::getCreateTime, todayStart));
+        if (todayCancelCount != null && todayCancelCount >= limit) {
+            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "浠婃棩鍙栨秷娆℃暟宸茶揪涓婇檺");
+        }
+
+        // 4. 閲嶇疆璁㈠崟鍙告満瀛楁锛堜繚鎸乻tatus=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(Constants.OrderLogType.driverCancel.getTitle());
+        log.setLogInfo(Constants.OrderLogType.driverCancel.format(StringUtils.isNotBlank(reason) ? reason : "鍙告満鍙栨秷鎺ュ崟"));
+        log.setObjType(Constants.OrderLogType.driverCancel.getStatus());
+        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());
+
+        // 閫氱煡鍙告満锛氬彇娑堟垚鍔�
+        int remainLimit = limit - (todayCancelCount != null ? todayCancelCount.intValue() + 1 : 1);
+        sendDriverNotice(driverId, Constants.DriverOrderNotify.CANCELLED, orderId,
+                "orderNo", order.getCode(),
+                "cancelLimit", String.valueOf(Math.max(remainLimit, 0)));
+    }
+
+    @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(Constants.OrderLogType.driverGrab.getTitle());
+        log.setLogInfo(Constants.OrderLogType.driverGrab.format(driver.getName()));
+        log.setObjType(Constants.OrderLogType.driverGrab.getStatus());
+        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());
+        }
+
+        // 閫氱煡鍙告満锛氭姠鍗曟垚鍔�
+        String shopName = order.getDepositShopName() != null ? order.getDepositShopName() : order.getDepositLocation();
+        sendDriverNotice(driverId, Constants.DriverOrderNotify.WAIT_DELIVER, orderId,
+                "orderNo", order.getCode(),
+                "shopName", shopName != null ? shopName : "");
+
+        // 鐭俊閫氱煡鍙告満锛氭姠鍗曟垚鍔燂紝寰呭彇浠�
+        String pickupAddress = order.getDepositShopAddress() != null ? order.getDepositShopAddress() : order.getDepositLocation();
+        sendSmsNotify(driver.getTelephone(), Constants.SmsNotify.DRIVER_WAIT_PICKUP,
+                "orderNo", order.getCode(),
+                "address", pickupAddress != null ? pickupAddress : "");
+    }
+
+    @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(Constants.OrderLogType.driverPickup.getTitle());
+        log.setLogInfo(Constants.OrderLogType.driverPickup.format(driver.getName()));
+        log.setObjType(Constants.OrderLogType.driverPickup.getStatus());
+        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());
+        }
+
+        // 閫氱煡鍙告満锛氬凡鍙栦欢閰嶉�佷腑
+        sendDriverNotice(driverId, Constants.DriverOrderNotify.DELIVERING, orderId,
+                "orderNo", order.getCode());
+
+        // 鐭俊閫氱煡浼氬憳锛氬徃鏈哄凡鍙栦欢锛岄厤閫佷腑
+        Member deliveringMember = memberMapper.selectById(order.getMemberId());
+        if (deliveringMember != null) {
+            sendSmsNotify(deliveringMember.getTelephone(), Constants.SmsNotify.MEMBER_DELIVERING,
+                    "orderNo", order.getCode(),
+                    "name", driver.getName());
+        }
+    }
+
+    @Override
+    @Transactional
+    public void confirmDeliver(Integer driverId, DriverDeliverDTO 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 (order.getTakeShopId() != null) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鏈夊彇浠堕棬搴楃殑璁㈠崟璇烽�佽揪鑷抽棬搴楁牳閿�");
+        }
+        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.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_DONE.getKey());
+                multifile.setType(Constants.ZERO);
+                multifile.setFileurl(url);
+                multifile.setIsdeleted(Constants.ZERO);
+                multifile.setCreateDate(now);
+                multifile.setSortnum(sortNum++);
+                multifileMapper.insert(multifile);
+            }
+        }
+
+        // 4. 鏇存柊璁㈠崟鐘舵�佷负宸查�佽揪(5)
+        ordersMapper.update(new UpdateWrapper<Orders>().lambda()
+                .set(Orders::getStatus, Constants.OrderStatus.arrived.getStatus())
+                .set(Orders::getArriveTime, now)
+                .set(Orders::getUpdateTime, now)
+                .eq(Orders::getId, orderId));
+
+        // 5. 鍐欏叆鎿嶄綔鏃ュ織
+        OrderLog log = new OrderLog();
+        log.setOrderId(orderId);
+        log.setTitle(Constants.OrderLogType.driverDeliver.getTitle());
+        log.setLogInfo(Constants.OrderLogType.driverDeliver.format(
+                StringUtils.isNotBlank(dto.getRemark()) ? dto.getRemark() : "鍙告満銆�" + driver.getName() + "銆戝凡閫佽揪"));
+        log.setObjType(Constants.OrderLogType.driverDeliver.getStatus());
+        log.setOptUserId(driver.getMemberId());
+        log.setOptUserType(Constants.ONE);
+        log.setOrderStatus(Constants.OrderStatus.arrived.getStatus());
+        log.setCreateTime(now);
+        log.setDeleted(Constants.ZERO);
+        orderLogMapper.insert(log);
+
+        // 6. 閫氱煡浼氬憳锛氳鍗曞凡閫佽揪锛堟棤鍙栦欢闂ㄥ簵锛�
+        String destination = StringUtils.isNotBlank(order.getTakeShopAddress()) ? order.getTakeShopAddress() : "鐩殑鍦�";
+        sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.ARRIVED_NO_SHOP, orderId,
+                "orderNo", order.getCode(),
+                "destination", destination);
+
+        // 閫氱煡鍙告満锛氬凡閫佽揪
+        sendDriverNotice(driverId, Constants.DriverOrderNotify.ARRIVED, orderId,
+                "orderNo", order.getCode(),
+                "destination", destination);
     }
 
     private List<String> getFileUrls(Integer orderId, int objType, String prefix) {
@@ -1178,4 +1726,99 @@
         return vo;
     }
 
+    /**
+     * 鍙戦�佺煭淇¢�氱煡锛堝け璐ヤ笉褰卞搷涓讳笟鍔★級
+     */
+    private void sendSmsNotify(String phone, Constants.SmsNotify smsNotify, String... paramPairs) {
+        if (StringUtils.isBlank(phone)) {
+            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(),
+                    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.setCreateTime(new Date());
+            record.setDeleted(Constants.ZERO);
+            smsrecordMapper.insert(record);
+        } catch (Exception e) {
+            log.error("鐭俊鍙戦�佸紓甯�: phone={}, template={}, error={}", phone, smsNotify.name(), e.getMessage());
+            try {
+                Smsrecord record = new Smsrecord();
+                record.setPhone(phone);
+                record.setContent(content);
+                record.setType(Constants.ONE);
+                record.setStatus(Constants.ZERO);
+                record.setCreateTime(new Date());
+                record.setDeleted(Constants.ZERO);
+                smsrecordMapper.insert(record);
+            } catch (Exception ignored) {}
+        }
+    }
+
+    @Override
+    public void changePassword(Integer driverId, String newPassword, String token) {
+        if (StringUtils.isBlank(newPassword)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀵嗙爜涓嶈兘涓虹┖");
+        }
+        // 鏍¢獙瀵嗙爜蹇呴』鍚屾椂鍖呭惈瀛楁瘝鍜屾暟瀛�
+        boolean hasLetter = newPassword.chars().anyMatch(Character::isLetter);
+        boolean hasDigit = newPassword.chars().anyMatch(Character::isDigit);
+        if (!hasLetter || !hasDigit) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀵嗙爜蹇呴』鍚屾椂鍖呭惈瀛楁瘝鍜屾暟瀛�");
+        }
+        // 鏌ヨ鍙告満瀵瑰簲鐨勪細鍛�
+        DriverInfo driverInfo = driverInfoMapper.selectById(driverId);
+        if (driverInfo == null || driverInfo.getMemberId() == null) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        Member member = memberMapper.selectById(driverInfo.getMemberId());
+        if (member == null) {
+            throw new BusinessException(ResponseStatus.DATA_EMPTY);
+        }
+        // 鍔犲瘑鏂板瘑鐮佸苟鏇存柊
+        String salt = RandomStringUtils.randomAlphanumeric(6);
+        String encryptPwd = secure.encryptPassword(newPassword, salt);
+        memberMapper.update(new UpdateWrapper<Member>().lambda()
+                .set(Member::getPassword, encryptPwd)
+                .set(Member::getSalt, salt)
+                .eq(Member::getId, member.getId()));
+        // 娓呴櫎token锛屽己鍒堕噸鏂扮櫥褰�
+        if (StringUtils.isNotBlank(token)) {
+            redisTemplate.delete(token);
+        }
+    }
+
+    @Override
+    public Map<String, Integer> getActiveOrderCount(Integer driverId) {
+        // 宸叉姠鍗�(status=3)鏁伴噺
+        Long grabbed = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getAcceptDriver, driverId)
+                .eq(Orders::getStatus, Constants.OrderStatus.accepted.getStatus())
+                .eq(Orders::getDeleted, Constants.ZERO));
+        // 娲鹃�佷腑(status=4)鏁伴噺
+        Long delivering = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda()
+                .eq(Orders::getAcceptDriver, driverId)
+                .eq(Orders::getStatus, Constants.OrderStatus.delivering.getStatus())
+                .eq(Orders::getDeleted, Constants.ZERO));
+        Map<String, Integer> result = new HashMap<>();
+        result.put("grabbedCount", grabbed != null ? grabbed.intValue() : 0);
+        result.put("deliveringCount", delivering != null ? delivering.intValue() : 0);
+        return result;
+    }
+
 }

--
Gitblit v1.9.3