rk
5 小时以前 c9f0611f690b3fb0cb120f5b6799f94977d3f129
代码生成
已添加4个文件
已修改14个文件
551 ■■■■■ 文件已修改
server/services/db/db_change.sql 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/config/alipay/AlipayFundTransUniTransfer.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/config/wx/WxPayProperties.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Orders.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/DriverActiveOrderDTO.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/DriverGrabOrderDTO.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/DriverGrabOrderVO.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/DriverOrderDetailVO.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/PriceCalculateVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/DriverInfoService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/OrdersService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/resources/application-dev.yml 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/resources/application-pro.yml 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/ConfigApi.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/DriverInfoApi.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/OrdersApi.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/db/db_change.sql
@@ -5,6 +5,12 @@
-- ============================================================
-- 2026/04/20 è®¢å•表增加物品级别字段
-- ============================================================
ALTER TABLE `orders` ADD COLUMN `GOOD_LEVEL` INT DEFAULT NULL COMMENT '物品级别(category主键,type=3)' AFTER `GOOD_TYPE`;
-- ============================================================
-- 2026/04/17 è®¢å•预计送达时间字段
-- ============================================================
ALTER TABLE `orders` ADD COLUMN `ESTIMATED_DELIVERY_TIME` DATETIME DEFAULT NULL COMMENT '预计送达时间' AFTER `CODE`;
server/services/src/main/java/com/doumee/config/alipay/AlipayFundTransUniTransfer.java
@@ -17,39 +17,29 @@
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        // åˆå§‹åŒ–alipay参数(全局设置一次)
        defaultClient.setAlipayConfig(getAlipayConfig());
        // æž„造请求参数以调用接口
        AlipayFundTransUniApi api = new AlipayFundTransUniApi();
        AlipayFundTransUniTransferModel data = new AlipayFundTransUniTransferModel();
        // è®¾ç½®å•†å®¶ä¾§å”¯ä¸€è®¢å•号
        data.setOutBizNo("202606300001");
        // è®¾ç½®è®¢å•总金额
        data.setTransAmount("1");
        // è®¾ç½®æè¿°ç‰¹å®šçš„业务场景
        data.setBizScene("DIRECT_TRANSFER");
        // è®¾ç½®ä¸šåŠ¡äº§å“ç 
        data.setProductCode("TRANS_ACCOUNT_NO_PWD");
        // è®¾ç½®è½¬è´¦ä¸šåŠ¡çš„æ ‡é¢˜
        data.setOrderTitle("201905代发");
        // è®¾ç½®åŽŸæ”¯ä»˜å®ä¸šåŠ¡å•å·
        data.setOriginalOrderId("20190620110075000006640000063056");
        // è®¾ç½®æ”¶æ¬¾æ–¹ä¿¡æ¯
        Participant payeeInfo = new Participant();
        payeeInfo.setIdentity("15345690849");
        payeeInfo.setName("江萍");
        payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
        data.setPayeeInfo(payeeInfo);
        // è®¾ç½®ä¸šåŠ¡å¤‡æ³¨
        data.setRemark("201905代发");
        // è®¾ç½®è½¬è´¦åœºæ™¯åç§°
        data.setTransferSceneName("佣金报酬");
@@ -74,7 +64,6 @@
        signData.setOriCharSet("UTF-8");
        data.setSignData(signData);
*/
        try {
            AlipayFundTransUniTransferResponseModel response = api.transfer(data);
        } catch (ApiException e) {
server/services/src/main/java/com/doumee/config/wx/WxPayProperties.java
@@ -46,4 +46,43 @@
     */
    private String keyPath;
    /**
     * apiV3Key
     */
    private String apiV3Key;
    /**
     * å•†æˆ·è¯ä¹¦åºåˆ—号
     */
    private String serialNumer;
    /**
     * é€€æ¬¾å›žè°ƒ
     */
    private String refundNotifyUrl;
    /**
     * å•†æˆ·æ”¯ä»˜å…¬é’¥
     */
    private String pubKeyPath;
    /**
     * æ”¯ä»˜ç§˜é’¥
     */
    private String privateCertPath;
    /**
     * æ”¯ä»˜key
     */
    private String privateKeyPath;
}
server/services/src/main/java/com/doumee/dao/business/model/Orders.java
@@ -191,6 +191,9 @@
    @ExcelColumn(name = "商品类型")
    private Integer goodType;
    @ApiModelProperty(value = "物品级别(category主键,type=3)")
    private Integer goodLevel;
    @ApiModelProperty(value = "补充信息")
    @ExcelColumn(name = "补充信息")
    private String supplement;
server/services/src/main/java/com/doumee/dao/dto/DriverActiveOrderDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.doumee.dao.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
 * å¸æœºè¿›è¡Œä¸­è®¢å•查询请求
 * @author rk
 * @date 2026/04/17
 */
@Data
@ApiModel("司机进行中订单查询请求")
public class DriverActiveOrderDTO {
    @NotNull(message = "订单状态不能为空")
    @ApiModelProperty(value = "订单状态:3=已抢单;4=派送中", example = "3", required = true)
    private Integer status;
}
server/services/src/main/java/com/doumee/dao/dto/DriverGrabOrderDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.doumee.dao.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
 * å¸æœºæŠ¢å•大厅查询请求
 * @author rk
 * @date 2026/04/17
 */
@Data
@ApiModel("司机抢单大厅查询请求")
public class DriverGrabOrderDTO implements Serializable {
    @ApiModelProperty(value = "排序类型:1=综合排序(创建时间倒序);2=距离最近(距存件门店距离升序)", example = "1")
    private Integer sortType;
    @ApiModelProperty(value = "物品等级ID(category type=3),筛选该等级下的所有物品分类", example = "5")
    private Integer gradeId;
    @ApiModelProperty(value = "距离筛选(单位:米),司机到存件门店的最大距离", example = "5000")
    private Integer distance;
}
server/services/src/main/java/com/doumee/dao/vo/DriverGrabOrderVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
package com.doumee.dao.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * å¸æœºæŠ¢å•大厅列表项
 * @author rk
 * @date 2026/04/17
 */
@Data
@ApiModel("司机抢单大厅列表项")
public class DriverGrabOrderVO implements Serializable {
    @ApiModelProperty(value = "订单主键")
    private Integer id;
    @ApiModelProperty(value = "订单编号")
    private String code;
    @ApiModelProperty(value = "剩余分钟数(当前时间到预计送达时间)")
    private Long remainMinutes;
    @ApiModelProperty(value = "是否加急:0=否;1=是")
    private Integer isUrgent;
    @ApiModelProperty(value = "存件门店名称")
    private String depositShopName;
    @ApiModelProperty(value = "存件门店地址")
    private String depositShopAddress;
    @ApiModelProperty(value = "距存件门店距离(如 500m、1.2km)")
    private String depositDistance;
    @ApiModelProperty(value = "取件名称(门店名称或自定义地点)")
    private String takeName;
    @ApiModelProperty(value = "取件距离(如 500m、1.2km)")
    private String takeDistance;
    @ApiModelProperty(value = "联系电话(status=2取件门店电话;status=3/4有取件门店返回门店电话,无则返回取件人电话)")
    private String contactPhone;
    @ApiModelProperty(value = "司机薪酬(分)")
    private Long driverFee;
    @ApiModelProperty(value = "加急费用(分)")
    private Long urgentAmount;
    @ApiModelProperty(value = "物品明细列表")
    private List<OrderItem> items;
    @ApiModelProperty(value = "是否贵重物品")
    private Boolean isValuable;
    @Data
    @ApiModel("抢单大厅物品项")
    public static class OrderItem implements Serializable {
        @ApiModelProperty(value = "物品名称")
        private String name;
        @ApiModelProperty(value = "数量")
        private Integer quantity;
    }
}
server/services/src/main/java/com/doumee/dao/vo/DriverOrderDetailVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
package com.doumee.dao.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * å¸æœºç«¯è®¢å•详情
 * @author rk
 * @date 2026/04/17
 */
@Data
@ApiModel("司机端订单详情")
public class DriverOrderDetailVO implements Serializable {
    @ApiModelProperty(value = "订单主键")
    private Integer id;
    @ApiModelProperty(value = "订单编号")
    private String code;
    @ApiModelProperty(value = "订单状态")
    private Integer status;
    @ApiModelProperty(value = "订单状态描述")
    private String statusDesc;
    @ApiModelProperty(value = "剩余分钟数(当前时间到预计送达时间)")
    private Long remainMinutes;
    @ApiModelProperty(value = "是否加急:0=否;1=是")
    private Integer isUrgent;
    @ApiModelProperty(value = "存件门店名称")
    private String depositShopName;
    @ApiModelProperty(value = "存件门店地址")
    private String depositShopAddress;
    @ApiModelProperty(value = "距存件门店距离(如 500m、1.2km)")
    private String depositDistance;
    @ApiModelProperty(value = "取件名称(门店名称或自定义地点)")
    private String takeName;
    @ApiModelProperty(value = "取件距离(如 500m、1.2km)")
    private String takeDistance;
    @ApiModelProperty(value = "联系电话")
    private String contactPhone;
    @ApiModelProperty(value = "司机薪酬(分)")
    private Long driverFee;
    @ApiModelProperty(value = "加急费用(分)")
    private Long urgentAmount;
    @ApiModelProperty(value = "物品明细列表")
    private List<OrderItem> items;
    @ApiModelProperty(value = "是否贵重物品")
    private Boolean isValuable;
    @ApiModelProperty(value = "导航纬度(status=2存件门店纬度,status=3/4取件纬度)")
    private Double navigateLat;
    @ApiModelProperty(value = "导航经度(status=2存件门店经度,status=3/4取件经度)")
    private Double navigateLng;
    @ApiModelProperty(value = "客户信息,如:刘先生(手机尾号1234)")
    private String customerInfo;
    @ApiModelProperty(value = "下单附件图片全路径列表")
    private List<String> orderImages;
    @Data
    @ApiModel("物品项")
    public static class OrderItem implements Serializable {
        @ApiModelProperty(value = "物品名称")
        private String name;
        @ApiModelProperty(value = "数量")
        private Integer quantity;
    }
}
server/services/src/main/java/com/doumee/dao/vo/PriceCalculateVO.java
@@ -35,6 +35,12 @@
    @ApiModelProperty("距离(km)")
    private BigDecimal distance;
    @ApiModelProperty("标速达预计时长(小时,上取整)")
    private Integer standardHours;
    @ApiModelProperty("极速达预计时长(小时,上取整)")
    private Integer urgentHours;
    @ApiModelProperty("天数")
    private Integer days;
}
server/services/src/main/java/com/doumee/service/business/DriverInfoService.java
@@ -215,4 +215,13 @@
     */
    com.doumee.dao.vo.DriverOrderDetailVO driverOrderDetail(Integer driverId, Integer orderId);
    /**
     * å¸æœºå–消订单(已接单status=2时取消,释放回抢单大厅)
     *
     * @param driverId å¸æœºä¸»é”®
     * @param orderId  è®¢å•主键
     * @param reason   å–消原因
     */
    void cancelOrder(Integer driverId, Integer orderId, String reason);
}
server/services/src/main/java/com/doumee/service/business/OrdersService.java
@@ -299,6 +299,15 @@
    void confirmStoreOut(Integer orderId, Integer shopId, List<String> images, String remark);
    /**
     * ä¼šå‘˜ç¡®è®¤æ”¶è´§
     * å¼‚地寄存且无取件门店的订单,送达后(status=5),会员确认收货标记订单完成
     *
     * @param orderId  è®¢å•主键
     * @param memberId å½“前登录会员ID
     */
    void memberConfirmReceipt(Integer orderId, Integer memberId);
    /**
     * è®¡ç®—并更新订单三方收益(存件门店/取件门店/司机)
     * å°±åœ°å¯„存:仅存件门店收益
     * å¼‚地寄存:存件门店 + å¸æœºæ”¶ç›Šï¼›æœ‰å–件门店时加上取件门店收益
server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -21,8 +21,11 @@
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;
@@ -98,6 +101,12 @@
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private OrderLogMapper orderLogMapper;
    @Autowired
    private OperationConfigBiz operationConfigBiz;
    @Override
    public Integer create(DriverInfo driverInfo) {
@@ -660,6 +669,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 +775,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 +823,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 +1067,72 @@
        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);
    }
    private List<String> getFileUrls(Integer orderId, int objType, String prefix) {
        List<Multifile> files = multifileMapper.selectList(
                new QueryWrapper<Multifile>().lambda()
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -536,6 +536,33 @@
        result.setUrgentFee(urgentFeeFen);
        result.setTotalPrice(totalPrice);
        result.setDistance(distanceKm);
        // 7. é¢„计送达时长:pricing_rule type=2(fieldA=1标速达,fieldA=2极速达)
        List<PricingRule> timeRules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda()
                .eq(PricingRule::getDeleted, Constants.ZERO)
                .eq(PricingRule::getType, Constants.TWO)
                .eq(PricingRule::getCityId, dto.getCityId())
                .in(PricingRule::getFieldA, Arrays.asList("1", "2")));
        for (PricingRule tr : timeRules) {
            BigDecimal baseKm = new BigDecimal(tr.getFieldB());
            int baseHours = Integer.parseInt(tr.getFieldC());
            BigDecimal extraKm = new BigDecimal(tr.getFieldD());
            int extraHours = Integer.parseInt(tr.getFieldE());
            int hours;
            if (distanceKm.compareTo(baseKm) <= 0) {
                hours = baseHours;
            } else {
                BigDecimal overDistance = distanceKm.subtract(baseKm);
                int extraCount = overDistance.divide(extraKm, 0, RoundingMode.CEILING).intValue();
                hours = baseHours + extraCount * extraHours;
            }
            if ("1".equals(tr.getFieldA())) {
                result.setStandardHours(hours);
            } else if ("2".equals(tr.getFieldA())) {
                result.setUrgentHours(hours);
            }
        }
        return result;
    }
@@ -742,6 +769,7 @@
        // ç‰©å“ä¿¡æ¯
        orders.setGoodType(dto.getGoodType());
        orders.setGoodLevel(goodTypeCategory.getRelationId());
        // æ‹¼æŽ¥ç‰©å“ä¿¡æ¯ï¼šç‰©å“ç±»åž‹åç§°ã€å°ºå¯¸åç§°*数量(数组字符串)
        List<String> goodsParts = new ArrayList<>();
        for (ItemPriceVO itemVO : priceResult.getItemList()) {
@@ -2339,6 +2367,43 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void memberConfirmReceipt(Integer orderId, Integer memberId) {
        // 1. æŸ¥è¯¢è®¢å•
        Orders order = ordersMapper.selectById(orderId);
        if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
        }
        // 2. æ ¡éªŒå½’属
        if (!memberId.equals(order.getMemberId())) {
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "无权操作该订单");
        }
        // 3. æ ¡éªŒè®¢å•类型:异地寄存
        if (!Constants.ONE.equals(order.getType())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅异地寄存订单可操作");
        }
        // 4. æ ¡éªŒæ— å–件门店
        if (order.getTakeShopId() != null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单有取件门店,需门店确认出库");
        }
        // 5. æ ¡éªŒçŠ¶æ€ï¼šå·²é€è¾¾(5)
        if (!Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许确认收货");
        }
        // 6. æ›´æ–°è®¢å•状态为已完成
        Date now = new Date();
        order.setStatus(Constants.OrderStatus.finished.getStatus());
        order.setFinishTime(now);
        order.setUpdateTime(now);
        ordersMapper.updateById(order);
        // 7. ç”Ÿæˆæ”¶ç›Šè®°å½•
        calculateAndSaveOrderFees(orderId);
        generateRevenueRecords(orderId);
    }
    @Override
    public void calculateAndSaveOrderFees(Integer orderId) {
        Orders order = ordersMapper.selectById(orderId);
        if (order == null || Constants.equalsInteger(order.getDeleted(), Constants.ONE)) {
server/services/src/main/resources/application-dev.yml
@@ -83,12 +83,25 @@
########################微信支付相关配置########################
wx:
  pay:
    appId: wxcd2b89fd2ff065f8
    appSecret: 3462fa186da7cb06c544df8d8664b63a
    mchId: 1229817002
    mchKey: u4TSNtv0wFP7WRfnxBgijYOtRhS9FvlM
    notifyUrl: http://xiaopiqiu2.natapp1.cc/web/api/wxPayNotify
    keyPath: D:\DouMee\dmkjWxcert\apiclient_cert.p12
#    appId: wxcd2b89fd2ff065f8
#    appSecret: 3462fa186da7cb06c544df8d8664b63a
#    mchId: 1229817002
#    mchKey: u4TSNtv0wFP7WRfnxBgijYOtRhS9FvlM
#    notifyUrl: http://xiaopiqiu2.natapp1.cc/web/api/wxPayNotify
#    keyPath: D:\DouMee\dmkjWxcert\apiclient_cert.p12
    appId: wxb1b59320e803dc6c
    appSecret: eb93785c7bca3f0ff0364b0e26bfeb59
    mchId: 1229817002    #商户号
    mchKey: u4TSNtv0wFP7WRfnxBgijYOtRhS9FvlM #商户秘钥
    apiV3Key: 7tG4Vk9Zp2L8dXw5Jq0N3hR6yE1sF3cB #apiV3Key
    serialNumer: 3FE90C2F3D40A56E1C51926F31B8A8D22426CCE0 #商户证书序列号
    notifyUrl: http://xiaopiqiu2.natapp1.cc/web/wxPayNotify
    refundNotifyUrl: http://xiaopiqiu2.natapp1.cc/web/wxRefundNotify
    keyPath: D:\DouMee\1229817002_20220310_cert\apiclient_cert.p12
    privateCertPath: D:\DouMee\1229817002_20220310_cert\apiclient_cert.pem
    privateKeyPath: D:\DouMee\1229817002_20220310_cert\apiclient_key.pem
    pubKeyPath: D:\DouMee\1229817002_20220310_cert\pub_key.pem #商户支付公钥
#    appId: wx6264b4f3a697cbe8
#    appSecret: 23734577e8978138c946b727f0394027
#    mchId: 1629568742
server/services/src/main/resources/application-pro.yml
@@ -52,39 +52,19 @@
########################微信支付相关配置########################
wx:
  pay:
    #服务商---------start------- å‚数详解地址 https://pay.weixin.qq.com/doc/v3/partner/4013080340
    mchId: 1700071922    #服务商在微信支付侧的唯一身份标识
    appId: wx6cc1087ca79db7f6    #服务商在微信开放平台(移动应用)或公众平台(公众号/小程序)上申请的一个唯一标识
    apiV3Key: 0a056faa107c2b2944b9d6a9aa6d4142 #7tG4Vk9Zp2L8dXw5Jq0N3hR6yE1sF3cB
    serialNumer: 6696086F6EFB8D6A4F821BD47DDBAF75C3BC1209 #38495CE0137D90E4DC4F64F7ECDE035A35470BE3 #服务商证书序列号
    payPublicKeyId: PUB_KEY_ID_0117000719222024112700219100000508 #商户/平台支付公钥id
    #mchKey: W97N53Q71326D6JZ2E9HY5M4VT4BAC8S
    notifyUrl: https://jinkuai.832smartfarm.com/jinkuai_admin/web/wxPayNotify
    refundNotifyUrl: https://jinkuai.832smartfarm.com/jinkuai_admin/web/wxRefundNotify
    keyPath: /usr/local/jars/payFile/apiclient_cert.p12
    privateCertPath: /usr/local/jars/payFile/apiclient_cert.pem
    privateKeyPath: /usr/local/jars/payFile/apiclient_key.pem
    pubKeyPath: /usr/local/jars/payFile/pub_key.pem #商户支付公钥
    appId: wxb1b59320e803dc6c
    appSecret: eb93785c7bca3f0ff0364b0e26bfeb59
    mchId: 1229817002    #商户号
    mchKey: u4TSNtv0wFP7WRfnxBgijYOtRhS9FvlM #商户秘钥
    apiV3Key: 7tG4Vk9Zp2L8dXw5Jq0N3hR6yE1sF3cB #apiV3Key
    serialNumer: 3FE90C2F3D40A56E1C51926F31B8A8D22426CCE0 #商户证书序列号
    notifyUrl: http://xiaopiqiu2.natapp1.cc/web/wxPayNotify
    refundNotifyUrl: http://xiaopiqiu2.natapp1.cc/web/wxRefundNotify
    keyPath: D:\DouMee\1229817002_20220310_cert\apiclient_cert.p12
    privateCertPath: D:\DouMee\1229817002_20220310_cert\apiclient_cert.pem
    privateKeyPath: D:\DouMee\1229817002_20220310_cert\apiclient_key.pem
    pubKeyPath: D:\DouMee\1229817002_20220310_cert\pub_key.pem #商户支付公钥
    #服务商-------------end---
    #商户信息
    wechatSerialNumer: 12C0F0DD0F3D2B565B45586D3FEA225EBF723BEC
    wechatPayPublicKeyId: PUB_KEY_ID_0117233260692025072500181939000603 #商户/平台支付公钥id
    wechatPubKeyPath: /usr/local/jars/payFile/shanghu/pub_key.pem #商户支付公钥
    wechatPrivateKeyPath: /usr/local/jars/payFile/shanghu/apiclient_key.pem #商户私钥
    wechatNotifyUrl: https://jinkuai.832smartfarm.com/jinkuai_admin/web/wechat/transferNotify #商户转账回调地址
    wechatApiV3Key: 7tG4Vk9Zp2L8dXw5Jq0N3hR6yE1sF3cB
    existsSub: 1
    appSecret:
    #子商户------------start----
    subMchId: 1723326069    #子商户号
    subAppId: wx332441ae5b12be7d #小程序id
    subAppSecret: add86d6406f5c14501ac5bbb1a60e004 #小程序秘钥
    #子商户------------end----
    #      mchKey: u4TSNtv0wFP7WRfnxBgijYOtRhS9FvlM
    typeId: jinkuai
alipay:
server/web/src/main/java/com/doumee/api/web/ConfigApi.java
@@ -7,6 +7,7 @@
import com.doumee.dao.business.model.Areas;
import com.doumee.dao.business.model.Banner;
import com.doumee.dao.business.model.Category;
import com.doumee.dao.dto.AreasDto;
import com.doumee.dao.dto.CalculateLocalPriceDTO;
import com.doumee.dao.dto.CalculateRemotePriceDTO;
import com.doumee.dao.dto.SameCityCheckDTO;
@@ -18,6 +19,7 @@
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -53,6 +55,15 @@
    @Autowired
    private MemberService memberService;
    @ApiOperation("全部区划树形查询")
    @PostMapping("/treeList")
    public ApiResponse<List<Areas>> treeList (@RequestBody AreasDto pageWrap) {
        Areas a = new Areas();
        BeanUtils.copyProperties(pageWrap,a);
        areasService.cacheData();
        return ApiResponse.success(areasService.findList(a));
    }
    @ApiOperation(value = "获取分类列表", notes = "小程序端")
    @GetMapping("/getCategoryList")
    @ApiImplicitParams({
server/web/src/main/java/com/doumee/api/web/DriverInfoApi.java
@@ -6,6 +6,7 @@
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.DriverInfo;
import com.doumee.dao.dto.DriverActiveOrderDTO;
import com.doumee.dao.dto.DriverGrabOrderDTO;
import com.doumee.dao.dto.DriverLoginRequest;
@@ -86,7 +87,7 @@
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse verifyDetail() {
    public ApiResponse<DriverInfo> verifyDetail() {
        return ApiResponse.success(driverInfoService.getVerifyDetail(this.getDriverId()));
    }
@@ -162,4 +163,17 @@
        return ApiResponse.success("操作成功", driverInfoService.driverOrderDetail(this.getDriverId(), orderId));
    }
    @LoginDriverRequired
    @Trace
    @ApiOperation(value = "司机取消订单", notes = "已接单(status=2)时取消,释放订单回抢单大厅")
    @PostMapping("/cancelOrder")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse cancelOrder(@RequestParam Integer orderId,
                                   @RequestParam(required = false) String reason) {
        driverInfoService.cancelOrder(this.getDriverId(), orderId, reason);
        return ApiResponse.success("取消成功");
    }
}
server/web/src/main/java/com/doumee/api/web/OrdersApi.java
@@ -214,5 +214,16 @@
        return ApiResponse.success("评价成功");
    }
    @LoginRequired
    @ApiOperation(value = "会员确认收货", notes = "异地寄存且无取件门店的订单,送达后确认收货标记订单完成")
    @PostMapping("/confirmReceipt")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse confirmReceipt(@RequestParam Integer orderId) {
        ordersService.memberConfirmReceipt(orderId, getMemberId());
        return ApiResponse.success("确认收货成功");
    }
}