rk
2 天以前 467fe3b3ec6aa9d449b094bdd9df4611323d88d1
代码生成
已添加2个文件
已修改34个文件
1221 ■■■■ 文件已修改
server/admin/src/main/java/com/doumee/api/business/OrdersController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/api/common/PublicCloudController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/config/jwt/JwtTokenUtil.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/constants/Constants.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/constants/ResponseStatus.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/utils/HttpsUtil.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/utils/jpush/JPushUtil.java 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/ConfirmArriveDTO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/DriverVerifyRequest.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/MyOrderDTO.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/dto/ShopVerifyDTO.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/DriverCenterVO.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/DriverStatsVO.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/MyOrderDetailVO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/MyOrderVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/vo/PlatformAboutVO.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/DriverInfoService.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/OrdersService.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/ShopInfoService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java 152 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java 274 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/RevenueServiceImpl.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/resources/application-dev.yml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/resources/application-pro.yml 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/AccountApi.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/ConfigApi.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/DriverInfoApi.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/OrdersApi.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/RevenueApi.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/ShopInfoApi.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/WalletApi.java 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/java/com/doumee/api/business/OrdersController.java
@@ -114,14 +114,6 @@
        return ApiResponse.success(null);
    }
    @ApiOperation("确认顾客到店")
    @PostMapping("/confirmArrived")
    @RequiresPermissions("business:orders:update")
    public ApiResponse confirmArrived(@RequestBody ConfirmArriveDTO dto) {
        ordersService.confirmCustomerArrived(dto.getOrderId(), dto.getShopId());
        return ApiResponse.success(null);
    }
    @ApiOperation("手动触发订单结算")
    @PostMapping("/settle")
    @RequiresPermissions("business:orders:update")
server/admin/src/main/resources/application.yml
@@ -12,7 +12,7 @@
spring:
  profiles:
    active: dev
    active: pro
  # JSON返回配置
  jackson:
    # é»˜è®¤æ—¶åŒº
server/services/src/main/java/com/doumee/api/common/PublicCloudController.java
@@ -84,7 +84,7 @@
                    // ç»çº¬åº¦æ°´å°å¤„理
                    InputStream uploadStream = is;
                    if (latitude != null && longitude != null) {
                    if (latitude != null && longitude != null && latitude > 0 && longitude > 0) {
                        try {
                            JSONObject geoResult = MapUtil.reverseGeocode(latitude, longitude);
                            String address = geoResult != null ? geoResult.getString("formatted_addresses") : "";
server/services/src/main/java/com/doumee/config/jwt/JwtTokenUtil.java
@@ -27,6 +27,10 @@
    public static final String HEADER_KEY = "token";
    public static final String SHOP_HEADER_KEY = "shopToken";
    public static final String MEMBER_ID = "MEMBER_ID";
    public static final String SHOP_ID = "SHOP_ID";
server/services/src/main/java/com/doumee/config/jwt/WebMvcConfig.java
@@ -74,19 +74,19 @@
                    }
                }else if (beanType.isAnnotationPresent(LoginShopRequired.class)) {
                    //获取token
                    String token = request.getHeader(JwtTokenUtil.HEADER_KEY);  // ä»Ž http è¯·æ±‚头中取出 token
                    String token = request.getHeader(JwtTokenUtil.SHOP_HEADER_KEY);  // ä»Ž http è¯·æ±‚头中取出 token
                    if (StringUtils.isNotBlank(token)) {
                        checkShopLogin(request,response);
                        checkShopLogin(token,request,response);
                    } else {
                        throw new BusinessException(ResponseStatus.BE_OVERDUE.getCode(),"未登录");
                        throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE.getCode(),"未登录");
                    }
                }else if (handlerMethod.hasMethodAnnotation(LoginShopRequired.class)){
                    //获取token
                    String token = request.getHeader(JwtTokenUtil.HEADER_KEY);  // ä»Ž http è¯·æ±‚头中取出 token
                    String token = request.getHeader(JwtTokenUtil.SHOP_HEADER_KEY);  // ä»Ž http è¯·æ±‚头中取出 token
                    if (StringUtils.isNotBlank(token)) {
                        checkShopLogin(request,response);
                        checkShopLogin(token,request,response);
                    } else {
                        throw new BusinessException(ResponseStatus.BE_OVERDUE.getCode(),"未登录");
                        throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE.getCode(),"未登录");
                    }
                }else if (beanType.isAnnotationPresent(LoginDriverRequired.class)) {
                    //获取token
@@ -144,19 +144,18 @@
    }
    public Boolean checkShopLogin(HttpServletRequest request, HttpServletResponse response){
        String token = request.getHeader(JwtTokenUtil.HEADER_KEY);
    public Boolean checkShopLogin(String token,HttpServletRequest request, HttpServletResponse response){
        try {
            if(!token.startsWith(Constants.TWO+"")){
                throw new BusinessException(ResponseStatus.TOKEN_EXCEED_TIME);
                throw new BusinessException(ResponseStatus.SHOP_TOKEN_EXCEED_TIME);
            }
            String tokenRedis = (String) redisTemplate.opsForValue().get(Constants.REDIS_TOKEN_KEY+token);
            if(StringUtils.isBlank(tokenRedis)){
                throw new BusinessException(ResponseStatus.BE_OVERDUE);
                throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE);
            }
            ShopInfo shop = JSONObject.parseObject(tokenRedis, ShopInfo.class);
            if(Objects.isNull(shop)){
                throw new BusinessException(ResponseStatus.BE_OVERDUE);
                throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE);
            }
            String openid = shop.getOpenid();
            Integer shopId = getTokenId(token);
@@ -170,17 +169,17 @@
            }
            String dbOpenid = dao.queryForObject(" select ifnull(openid,'')  from shop_info where id  = ?", String.class, shopId);
            if(StringUtils.isBlank(dbOpenid)||!openid.equals(dbOpenid)){
                throw new BusinessException(ResponseStatus.TOKEN_EXCEED_TIME);
                throw new BusinessException(ResponseStatus.SHOP_TOKEN_EXCEED_TIME);
            }
            Integer count = dao.queryForObject("select count(1) from shop_info where id  = ?", Integer.class, shopId);
            if (count != null && count > 0) {
                request.setAttribute(JwtTokenUtil.SHOP_ID, shop.getId());
                return true;
            }else{
                throw new BusinessException(ResponseStatus.BE_OVERDUE.getCode(),"用户信息出错");
                throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE.getCode(),"用户信息出错");
            }
        } catch (IllegalArgumentException | JwtException e) {
            throw new BusinessException(ResponseStatus.BE_OVERDUE);
            throw new BusinessException(ResponseStatus.SHOP_BE_OVERDUE);
        }
    }
server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -50,6 +50,22 @@
    public static final String USER_AGREEMENT ="USER_AGREEMENT" ;
    public static final String PRIVACY_AGREEMENT ="PRIVACY_AGREEMENT" ;
    public static final String STORE_RISK_COMMITMENT = "STORE_RISK_COMMITMENT";
    public static final String STORE_COOPERATION_AGREEMENT = "STORE_COOPERATION_AGREEMENT";
    public static final String STORE_LUGGAGE_STORAGE_NOTICE = "STORE_LUGGAGE_STORAGE_NOTICE";
    public static final String STORE_PRIVACY_POLICY = "STORE_PRIVACY_POLICY";
    public static final String OWNER_LUGGAGE_STORAGE_NOTICE = "OWNER_LUGGAGE_STORAGE_NOTICE";
    public static final String OWNER_SERVICE_AGREEMENT = "OWNER_SERVICE_AGREEMENT";
    public static final String OWNER_RISK_COMMITMENT = "OWNER_RISK_COMMITMENT";
    public static final String ERRAND_RISK_COMMITMENT = "ERRAND_RISK_COMMITMENT";
    public static final String ERRAND_SERVICE_AGREEMENT = "ERRAND_SERVICE_AGREEMENT";
    public static final String ERRAND_LUGGAGE_STORAGE_NOTICE = "ERRAND_LUGGAGE_STORAGE_NOTICE";
    public static final String USER_SERVICE_AGREEMENT = "USER_SERVICE_AGREEMENT";
    public static final String USER_PRIVACY_POLICY = "USER_PRIVACY_POLICY";
    public static final String DRIVER_PRIVACY_POLICY = "DRIVER_PRIVACY_POLICY";
    public static final String PRICE_DESCRIPTION = "PRICE_DESCRIPTION";
    public static final String PROHIBITED_ITEMS = "PROHIBITED_ITEMS";
    public static final String ACCESS_ID="ACCESS_ID";
    public static final String BUCKETNAME = "BUCKETNAME";
@@ -64,6 +80,7 @@
    public static final Integer FOUR = 4;
    public static final Integer SIX = 6;
    public static final Integer FIVE = 5;
    public static final Integer SEVEN = 7;
    public static final String INENTITY_FILES = "INENTITY_FILES";
    public static final String MEMBER_FILES = "MEMBER_FILES";
    public static final String CATEGORY_FILES = "CATEGORY_FILES";
@@ -392,7 +409,7 @@
                        if(Constants.equalsInteger(type,Constants.ZERO)){
                            return "待取件";
                        }else{
                            return Constants.equalsInteger(type,Constants.ONE)?"已到店":"已送达";
                            return "已送达";
                        }
                    }
                    return c.getValue();
@@ -413,9 +430,11 @@
        waitDeliver(2, "待配送", new int[]{OrderStatus.accepted.status}),
        waitReceive(3, "待收货", new int[]{ OrderStatus.delivering.status, OrderStatus.arrived.status}),
        finished(4, "已完成", new int[]{OrderStatus.finished.status}),
        refund(5, "退款", new int[]{OrderStatus.cancelled.status}),
        refund(5, "取消", new int[]{OrderStatus.cancelled.status}),
        home(6, "首页查询", new int[]{OrderStatus.waitPay.status, OrderStatus.waitDeposit.status, OrderStatus.deposited.status
                , OrderStatus.accepted.status, OrderStatus.delivering.status, OrderStatus.arrived.status})
                , OrderStatus.accepted.status, OrderStatus.delivering.status, OrderStatus.arrived.status}),
        shopHome(7, "门店首页查询", new int[]{OrderStatus.waitDeposit.status, OrderStatus.deposited.status
                , OrderStatus.delivering.status, OrderStatus.arrived.status})
        ;
        private final int key;
        private final String desc;
server/services/src/main/java/com/doumee/core/constants/ResponseStatus.java
@@ -30,6 +30,9 @@
    NOT_ALLOWED(5110, "不允许的操作"),
    BE_OVERDUE(5112, "未登录"),
    TOKEN_EXCEED_TIME(5113, "对不起,登录已失效!"),
    SHOP_BE_OVERDUE(51121, "未登录"),
    SHOP_TOKEN_EXCEED_TIME(51131, "对不起,登录已失效!"),
    ;
    private int code;
server/services/src/main/java/com/doumee/core/utils/HttpsUtil.java
@@ -26,6 +26,13 @@
            return connectionHttp(url, "POST", data, "application/json");
        }
    }
    public static String postJson(String url, String data, String authorization) {
        if(url.startsWith("https://")){
            return connection(url, "POST", data, "application/json", true, authorization);
        }else{
            return connectionHttp(url, "POST", data, "application/json", authorization);
        }
    }
    public static String uploadTempMedia(String urlString ,String fileUrl){
        HttpsURLConnection conn= null;
        try {
@@ -101,6 +108,9 @@
    }
    public static String connection(String url,String method,String data,String contentType,boolean ignoreSSL){
        return connection(url, method, data, contentType, ignoreSSL, null);
    }
    public static String connection(String url,String method,String data,String contentType,boolean ignoreSSL, String authorization){
        HttpsURLConnection connection = null;
        try {
            URL _url = new URL(url);
@@ -111,6 +121,9 @@
            connection.setUseCaches(false);
            if(contentType != null){
                connection.setRequestProperty("Content-Type", contentType);
            }
            if(authorization != null){
                connection.setRequestProperty("Authorization", authorization);
            }
            if(ignoreSSL){
@@ -172,6 +185,9 @@
        return null;
    }
    public static String connectionHttp(String url,String method,String data,String contentType ){
        return connectionHttp(url, method, data, contentType, null);
    }
    public static String connectionHttp(String url,String method,String data,String contentType, String authorization ){
        HttpURLConnection connection = null;
        try {
            URL _url = new URL(url);
@@ -183,6 +199,9 @@
            if(contentType != null){
                connection.setRequestProperty("Content-Type", contentType);
            }
            if(authorization != null){
                connection.setRequestProperty("Authorization", authorization);
            }
            connection.connect();
server/services/src/main/java/com/doumee/core/utils/jpush/JPushUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,239 @@
package com.doumee.core.utils.jpush;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.doumee.core.utils.HttpsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
 * æžå…‰æŽ¨é€å·¥å…·ç±»ï¼ˆåŸºäºŽJPush REST API)
 *
 * @author rk
 * @date 2026/04/24
 */
@Component
@Slf4j
public class JPushUtil {
    private static final String PUSH_URL = "https://bjapi.push.jiguang.cn/v3/push";
    private static String authHeader;
    private static boolean apnsProduction;
    @Value("${jpush.appKey:}")
    private String appKey;
    @Value("${jpush.masterSecret:}")
    private String masterSecret;
    @Value("${jpush.apnsProduction:false}")
    private boolean apnsProd;
    @PostConstruct
    public void init() {
        if (StringUtils.isNotBlank(appKey) && StringUtils.isNotBlank(masterSecret)) {
            authHeader = "Basic " + Base64.getEncoder().encodeToString((appKey + ":" + masterSecret).getBytes());
            apnsProduction = apnsProd;
            log.info("JPush initialized, appKey={}", appKey);
        } else {
            log.warn("JPush not configured, push disabled");
        }
    }
    // ==================== é€šçŸ¥æ æŽ¨é€ ====================
    /**
     * æŒ‰åˆ«åæŽ¨é€é€šçŸ¥
     *
     * @param alias   åˆ«åï¼ˆå¦‚会员ID/司机ID/门店ID)
     * @param title   é€šçŸ¥æ ‡é¢˜
     * @param content é€šçŸ¥å†…容
     * @param extras  é™„加字段(可选)
     * @return æ˜¯å¦æŽ¨é€æˆåŠŸ
     */
    public static boolean sendByAlias(String alias, String title, String content, Map<String, String> extras) {
        return sendByAliases(Collections.singletonList(alias), title, content, extras);
    }
    /**
     * æŒ‰åˆ«åæ‰¹é‡æŽ¨é€é€šçŸ¥
     */
    public static boolean sendByAliases(List<String> aliases, String title, String content, Map<String, String> extras) {
        if (!available() || aliases == null || aliases.isEmpty()) {
            return false;
        }
        JSONObject body = buildNotificationBody(aliases, "alias", title, content, extras);
        return doPush(body, "sendByAliases");
    }
    /**
     * æŒ‰RegistrationId推送通知
     */
    public static boolean sendByRegId(String regId, String title, String content, Map<String, String> extras) {
        return sendByRegIds(Collections.singletonList(regId), title, content, extras);
    }
    /**
     * æŒ‰RegistrationId批量推送通知
     */
    public static boolean sendByRegIds(List<String> regIds, String title, String content, Map<String, String> extras) {
        if (!available() || regIds == null || regIds.isEmpty()) {
            return false;
        }
        JSONObject body = buildNotificationBody(regIds, "registration_id", title, content, extras);
        return doPush(body, "sendByRegIds");
    }
    /**
     * å¹¿æ’­æŽ¨é€é€šçŸ¥ï¼ˆæŽ¨é€ç»™æ‰€æœ‰ç”¨æˆ·ï¼‰
     */
    public static boolean sendToAll(String title, String content, Map<String, String> extras) {
        if (!available()) {
            return false;
        }
        JSONObject body = buildNotificationBody(null, "all", title, content, extras);
        return doPush(body, "sendToAll");
    }
    // ==================== è‡ªå®šä¹‰æ¶ˆæ¯ï¼ˆé™é»˜æŽ¨é€ï¼Œä¸æ˜¾ç¤ºé€šçŸ¥æ ï¼‰ ====================
    /**
     * æŒ‰åˆ«åæŽ¨é€è‡ªå®šä¹‰æ¶ˆæ¯
     */
    public static boolean sendMessageByAlias(String alias, String content, Map<String, String> extras) {
        return sendMessagesByAlias(Collections.singletonList(alias), content, extras);
    }
    /**
     * æŒ‰åˆ«åæ‰¹é‡æŽ¨é€è‡ªå®šä¹‰æ¶ˆæ¯
     */
    public static boolean sendMessagesByAlias(List<String> aliases, String content, Map<String, String> extras) {
        if (!available() || aliases == null || aliases.isEmpty()) {
            return false;
        }
        JSONObject body = buildMessageBody(aliases, "alias", content, extras);
        return doPush(body, "sendMessageByAlias");
    }
    // ==================== å†…部方法 ====================
    private static boolean available() {
        return StringUtils.isNotBlank(authHeader);
    }
    /**
     * æž„建通知栏推送请求体
     */
    private static JSONObject buildNotificationBody(List<String> targets, String audienceType,
                                                    String title, String content, Map<String, String> extras) {
        JSONObject body = new JSONObject();
        // platform
        body.put("platform", "all");
        // audience
        if ("all".equals(audienceType)) {
            body.put("audience", "all");
        } else {
            JSONObject audience = new JSONObject();
            JSONArray arr = new JSONArray();
            arr.addAll(targets);
            audience.put(audienceType, arr);
            body.put("audience", audience);
        }
        // notification
        JSONObject notification = new JSONObject();
        // Android
        JSONObject android = new JSONObject();
        android.put("title", title);
        android.put("alert", content);
        if (extras != null && !extras.isEmpty()) {
            android.put("extras", mapToJson(extras));
        }
        notification.put("android", android);
        // iOS
        JSONObject ios = new JSONObject();
        ios.put("alert", content);
        ios.put("sound", "default");
        if (extras != null && !extras.isEmpty()) {
            ios.put("extras", mapToJson(extras));
        }
        notification.put("ios", ios);
        body.put("notification", notification);
        // options
        JSONObject options = new JSONObject();
        options.put("apns_production", apnsProduction);
        body.put("options", options);
        return body;
    }
    /**
     * æž„建自定义消息请求体(不显示通知栏)
     */
    private static JSONObject buildMessageBody(List<String> targets, String audienceType,
                                               String content, Map<String, String> extras) {
        JSONObject body = new JSONObject();
        body.put("platform", "all");
        JSONObject audience = new JSONObject();
        JSONArray arr = new JSONArray();
        arr.addAll(targets);
        audience.put(audienceType, arr);
        body.put("audience", audience);
        // message
        JSONObject message = new JSONObject();
        message.put("msg_content", content);
        if (extras != null && !extras.isEmpty()) {
            message.put("extras", mapToJson(extras));
        }
        body.put("message", message);
        JSONObject options = new JSONObject();
        options.put("apns_production", apnsProduction);
        body.put("options", options);
        return body;
    }
    /**
     * Map<String, String> â†’ JSONObject
     */
    private static JSONObject mapToJson(Map<String, String> map) {
        JSONObject json = new JSONObject();
        json.putAll(map);
        return json;
    }
    /**
     * æ‰§è¡ŒæŽ¨é€è¯·æ±‚
     */
    private static boolean doPush(JSONObject body, String action) {
        try {
            String response = HttpsUtil.postJson(PUSH_URL, body.toJSONString(), authHeader);
            log.info("JPush {}, response={}", action, response);
            if (StringUtils.isNotBlank(response)) {
                JSONObject resp = JSONObject.parseObject(response);
                return resp.containsKey("msg_id") || (resp.containsKey("statusCode") && resp.getIntValue("statusCode") == 0);
            }
            return false;
        } catch (Exception e) {
            log.error("JPush {} error", action, e);
            return false;
        }
    }
}
server/services/src/main/java/com/doumee/dao/business/model/DriverInfo.java
@@ -100,8 +100,8 @@
    @ExcelColumn(name = "状态", index = 8, width = 8, valueMapping = "0=启用;1=禁用;")
    private Integer status;
    @ApiModelProperty(value = "审批状态:0=待审批;1=审批通过;2=审批驳回", example = "0")
    @ExcelColumn(name = "审批状态", index = 9, width = 10, valueMapping = "0=待审批;1=审批通过;2=审批驳回")
    @ApiModelProperty(value = "审批状态:0=待审批;1=审批通过;2=审批驳回;3=已支付押金;99=未认证;", example = "0")
    @ExcelColumn(name = "审批状态", index = 9, width = 10, valueMapping = "审批状态:0=待审批;1=审批通过;2=审批驳回;3=已支付押金;99=未认证;")
    private Integer auditStatus;
    @ApiModelProperty(value = "OPENID(APP)")
@@ -203,4 +203,30 @@
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createTimeEnd;
    // ---- çœå¸‚区信息(非数据库字段) ----
    @TableField(exist = false)
    @ApiModelProperty(value = "省份主键")
    private Integer provinceId;
    @TableField(exist = false)
    @ApiModelProperty(value = "省份名称")
    private String provinceName;
    @TableField(exist = false)
    @ApiModelProperty(value = "城市主键")
    private Integer cityId;
    @TableField(exist = false)
    @ApiModelProperty(value = "城市名称")
    private String cityName;
    @TableField(exist = false)
    @ApiModelProperty(value = "区县主键")
    private Integer districtId;
    @TableField(exist = false)
    @ApiModelProperty(value = "区县名称")
    private String districtName;
}
server/services/src/main/java/com/doumee/dao/dto/ConfirmArriveDTO.java
@@ -19,7 +19,4 @@
    @ApiModelProperty(value = "订单主键", required = true)
    private Integer orderId;
    @NotNull(message = "门店主键不能为空")
    @ApiModelProperty(value = "当前操作门店主键", required = true)
    private Integer shopId;
}
server/services/src/main/java/com/doumee/dao/dto/DriverVerifyRequest.java
@@ -1,5 +1,6 @@
package com.doumee.dao.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -50,9 +51,11 @@
    private String carColor;
    @ApiModelProperty(value = "驾驶证有效期开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date cardStartDate;
    @ApiModelProperty(value = "驾驶证有效期结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date cardEndDate;
    @NotEmpty(message = "身份证正面照不能为空")
server/services/src/main/java/com/doumee/dao/dto/MyOrderDTO.java
@@ -18,7 +18,7 @@
    @ApiModelProperty(value = "订单状态(可选,不传查全部)", example = "0")
    private Integer status;
    @ApiModelProperty(value = "合并状态(可选,不传查全部): 0=待支付 1=待核验 2=待配送 3=待收货 4=已完成 5=退款", example = "0")
    @ApiModelProperty(value = "合并状态(可选,不传查全部): 0=待支付 1=待核验 2=待配送 3=待收货 4=已完成 5=退款 6会员首页 7门店待处理订单", example = "0")
    private Integer combinedStatus;
}
server/services/src/main/java/com/doumee/dao/dto/ShopVerifyDTO.java
@@ -4,7 +4,7 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
@@ -18,9 +18,9 @@
@ApiModel("门店核销请求")
public class ShopVerifyDTO {
    @NotBlank(message = "核销码不能为空")
    @ApiModelProperty(value = "会员核销码", required = true)
    private String verifyCode;
    @NotNull(message = "订单主键不能为空")
    @ApiModelProperty(value = "订单主键", required = true)
    private Integer orderId;
    @Size(max = 3, message = "最多上传3张图片")
    @ApiModelProperty(value = "图片地址列表,最多3å¼ ")
server/services/src/main/java/com/doumee/dao/vo/DriverCenterVO.java
@@ -28,6 +28,15 @@
    @ApiModelProperty(value = "服务评分")
    private String score;
    @ApiModelProperty(value = "司机定级:5=S 4=A 3=B 2=C 1=D")
    private Integer driverLevel;
    @ApiModelProperty(value = "审核状态:0=待审批 1=审批通过 2=审批驳回")
    private Integer auditStatus;
    @ApiModelProperty(value = "审核备注(驳回原因)")
    private String auditRemark;
    @ApiModelProperty(value = "今日预计佣金(分)")
    private Long todayCommission;
@@ -43,4 +52,8 @@
    @ApiModelProperty(value = "待配送订单数量")
    private Integer waitDeliverCount;
    @ApiModelProperty(value = "是否接单中:0=已下线;1=接单中", example = "0")
    private Integer acceptingStatus;
}
server/services/src/main/java/com/doumee/dao/vo/DriverStatsVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.doumee.dao.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * å¸æœºç´¯è®¡ç»Ÿè®¡
 *
 * @author rk
 * @date 2026/04/24
 */
@Data
@ApiModel("司机累计统计")
public class DriverStatsVO {
    @ApiModelProperty(value = "累计佣金(分)")
    private Long totalCommission;
    @ApiModelProperty(value = "待结算佣金(分)")
    private Long pendingCommission;
    @ApiModelProperty(value = "订单总数")
    private Integer totalOrderCount;
    @ApiModelProperty(value = "钱包余额(分)")
    private Long balance;
}
server/services/src/main/java/com/doumee/dao/vo/MyOrderDetailVO.java
@@ -134,7 +134,8 @@
    // ---- é€¾æœŸ ----
    @ApiModelProperty(value = "逾期状态: 0=无逾期 1=存在逾期 2=待支付逾期 3=逾期已支付")
    //逾期状态: 0=未到店未逾期 1=未到店存在逾期 2=已到店未存在逾期 3=已到店待支付逾期 4=逾期已支付
    @ApiModelProperty(value = "逾期状态: 0=未到店未逾期 1=未到店存在逾期 2=已到店未逾期 3=已到店待支付逾期 4=逾期已支付")
    private Integer overdueStatus;
    @ApiModelProperty(value = "是否逾期")
server/services/src/main/java/com/doumee/dao/vo/MyOrderVO.java
@@ -37,6 +37,9 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    @ApiModelProperty(value = "订单备注")
    private String remark;
    @ApiModelProperty(value = "预计取件时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date expectedTakeTime;
@@ -94,6 +97,9 @@
    // ---- é€¾æœŸ ----
    @ApiModelProperty(value = "逾期状态:0=未到店未逾期;1=未到店存在逾期;2=已到店未逾期;3=已到店待支付逾期;4=逾期已支付")
    private Integer overdueStatus;
    @ApiModelProperty(value = "是否逾期")
    private Boolean overdue;
server/services/src/main/java/com/doumee/dao/vo/PlatformAboutVO.java
@@ -4,6 +4,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Map;
/**
 * å¹³å°ä¿¡æ¯ï¼ˆå…³äºŽæˆ‘们、协议等)
 *
@@ -17,12 +19,6 @@
    @ApiModelProperty(value = "关于我们")
    private String aboutUs;
    @ApiModelProperty(value = "用户协议")
    private String userAgreement;
    @ApiModelProperty(value = "隐私协议")
    private String privacyAgreement;
    @ApiModelProperty(value = "规范须知")
    private String serverIntroduce;
    @ApiModelProperty(value = "协议须知列表,key=枚举编码,value=富文本内容")
    private Map<String, String> agreements;
}
server/services/src/main/java/com/doumee/service/business/DriverInfoService.java
@@ -13,6 +13,7 @@
import com.doumee.dao.vo.AccountResponse;
import java.util.List;
import java.util.Map;
/**
 * å¸æœºæ³¨å†Œä¿¡æ¯Service定义
@@ -191,6 +192,11 @@
    com.doumee.dao.vo.DriverCenterVO getDriverCenterInfo(Integer memberId);
    /**
     * å¸æœºç´¯è®¡ç»Ÿè®¡ï¼ˆç´¯è®¡ä½£é‡‘、待结算佣金、订单总数、钱包余额)
     */
    com.doumee.dao.vo.DriverStatsVO getDriverStats(Integer memberId);
    /**
     * å¸æœºæŠ¢å•大厅 - åˆ†é¡µæŸ¥è¯¢å¯æŠ¢è®¢å•
     *
     * @param memberId  å½“前登录会员主键
@@ -250,4 +256,21 @@
     */
    void confirmDeliver(Integer driverId, DriverDeliverDTO dto);
    /**
     * å¸æœºä¿®æ”¹å¯†ç 
     *
     * @param driverId    å¸æœºä¸»é”®
     * @param newPassword æ–°å¯†ç 
     * @param token       å½“前token(修改成功后清除)
     */
    void changePassword(Integer driverId, String newPassword, String token);
    /**
     * èŽ·å–å¸æœºè¿›è¡Œä¸­è®¢å•æ•°é‡
     *
     * @param driverId å¸æœºä¸»é”®
     * @return [已抢单数量, æ´¾é€ä¸­æ•°é‡]
     */
    Map<String, Integer> getActiveOrderCount(Integer driverId);
}
server/services/src/main/java/com/doumee/service/business/OrdersService.java
@@ -149,6 +149,26 @@
    void shopVerifyOrder(String verifyCode, Integer shopId, List<String> images, String remark);
    /**
     * é—¨åº—核销(自动识别会员核销码/司机核销码)
     *
     * @param verifyCode æ ¸é”€ç 
     * @param shopId     é—¨åº—主键
     * @param images     å›¾ç‰‡
     * @param remark     å¤‡æ³¨
     */
    void verifyOrder(String verifyCode, Integer shopId, List<String> images, String remark);
    /**
     * é—¨åº—通过订单主键核销
     *
     * @param orderId è®¢å•主键
     * @param shopId  é—¨åº—主键
     * @param images  å›¾ç‰‡
     * @param remark  å¤‡æ³¨
     */
    void verifyOrderByShopId(Integer orderId, Integer shopId, List<String> images, String remark);
    /**
     * é—¨åº—端查询订单详情
     * æ”¯æŒæŒ‰è®¢å•主键或核销码查询,复用会员端详情逻辑
     *
server/services/src/main/java/com/doumee/service/business/ShopInfoService.java
@@ -209,4 +209,13 @@
     */
    ShopSalesStatsVO getShopSalesStats(Integer shopId, Integer period);
    /**
     * é—¨åº—修改密码
     *
     * @param shopId      é—¨åº—主键
     * @param newPassword æ–°å¯†ç 
     * @param token       å½“前token(修改成功后清除)
     */
    void changePassword(Integer shopId, String newPassword, String token);
}
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;
@@ -22,27 +23,17 @@
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.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.OrderComment;
import com.doumee.dao.business.model.ShopInfo;
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.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;
@@ -118,6 +109,9 @@
    @Autowired
    private NoticeService noticeService;
    @Autowired
    private AreasBizImpl areasBiz;
    /**
     * å‘送订单站内信通知
@@ -383,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));
@@ -401,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);
        }
@@ -531,6 +527,7 @@
                .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()));
@@ -561,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());
            }
        }
        // æŸ¥è¯¢ç…§ç‰‡åˆ—表
@@ -790,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()
@@ -840,6 +861,54 @@
                .eq(Orders::getDeleted, Constants.ZERO)
                .eq(Orders::getStatus, Constants.OrderStatus.delivering.getStatus()));
        vo.setWaitDeliverCount(waitDeliverCount.intValue());
        return vo;
    }
    @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();
        // ç´¯è®¡ä½£é‡‘:type=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;
    }
@@ -1701,4 +1770,55 @@
        }
    }
    @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;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -48,7 +48,9 @@
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@@ -440,9 +442,34 @@
    public PlatformAboutVO getPlatformAboutUs(){
        PlatformAboutVO vo = new PlatformAboutVO();
        vo.setAboutUs(StringUtils.trimToNull(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.ABOUT_US).getCode()));
        vo.setUserAgreement(StringUtils.trimToNull(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.USER_AGREEMENT).getCode()));
        vo.setPrivacyAgreement(StringUtils.trimToNull(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.PRIVACY_AGREEMENT).getCode()));
        vo.setServerIntroduce(StringUtils.trimToNull(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.SERVER_INTRODUCE).getCode()));
        Map<String, String> agreements = new LinkedHashMap<>();
        String[] agreementKeys = {
                Constants.STORE_RISK_COMMITMENT,
                Constants.STORE_COOPERATION_AGREEMENT,
                Constants.STORE_LUGGAGE_STORAGE_NOTICE,
                Constants.STORE_PRIVACY_POLICY,
                Constants.OWNER_LUGGAGE_STORAGE_NOTICE,
                Constants.OWNER_SERVICE_AGREEMENT,
                Constants.OWNER_RISK_COMMITMENT,
                Constants.ERRAND_RISK_COMMITMENT,
                Constants.ERRAND_SERVICE_AGREEMENT,
                Constants.ERRAND_LUGGAGE_STORAGE_NOTICE,
                Constants.USER_SERVICE_AGREEMENT,
                Constants.USER_PRIVACY_POLICY,
                Constants.DRIVER_PRIVACY_POLICY,
                Constants.PRICE_DESCRIPTION,
                Constants.PROHIBITED_ITEMS
        };
        for (String key : agreementKeys) {
            try {
                String value = StringUtils.trimToNull(systemDictDataBiz.queryByCode(Constants.SYSTEM, key).getCode());
                agreements.put(key, value);
            } catch (Exception e) {
                agreements.put(key, null);
            }
        }
        vo.setAgreements(agreements);
        return vo;
    }
server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -1461,13 +1461,8 @@
                // ç‰©å“æ˜Žç»†
                vo.setDetailList(buildDetailList(details));
                // é€¾æœŸä¿¡æ¯ï¼ˆä»…待取件状态计算)
                if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) {
                    OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details);
                    vo.setOverdue(overdueInfo.getOverdue());
                    vo.setOverdueDays(overdueInfo.getOverdueDays());
                    vo.setOverdueFee(overdueInfo.getOverdueFee());
                }
                // é€¾æœŸçŠ¶æ€
                fillOverdueStatus(vo, o, details);
                voList.add(vo);
            }
        }
@@ -1513,10 +1508,24 @@
                .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID")
                .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID")
                .leftJoin("driver_info d on d.id = t.ACCEPT_DRIVER")
                .eq(Orders::getPayStatus, Constants.ONE)
                .and(w -> w.eq(Orders::getDepositShopId, shopId).or().eq(Orders::getTakeShopId, shopId))
                .eq(status != null, Orders::getStatus, status)
                .in(statusList != null, Orders::getStatus, statusList)
                .eq(Orders::getPayStatus, Constants.ONE);
        // é—¨åº—待处理订单:按业务环节区分门店角色
        if (combinedStatus != null && Constants.equalsInteger(combinedStatus, Constants.SEVEN)) {
            wrapper.and(w -> w
                    .and(w1 -> w1.eq(Orders::getDepositShopId, shopId)
                            .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getStatus(),
                                    Constants.OrderStatus.deposited.getStatus()))
                    .or(w2 -> w2.eq(Orders::getTakeShopId, shopId)
                            .in(Orders::getStatus, Constants.OrderStatus.delivering.getStatus(),
                                    Constants.OrderStatus.arrived.getStatus()))
            );
        } else {
            wrapper.and(w -> w.eq(Orders::getDepositShopId, shopId).or().eq(Orders::getTakeShopId, shopId));
        }
        wrapper.eq(status != null, Orders::getStatus, status)
                .in(statusList != null && !Constants.equalsInteger(combinedStatus, Constants.SEVEN), Orders::getStatus, statusList)
                .orderByDesc(Orders::getCreateTime);
        IPage<Orders> orderPage = ordersMapper.selectJoinPage(p, Orders.class, wrapper);
@@ -1532,6 +1541,7 @@
                        Constants.equalsInteger(o.getType(), Constants.ZERO)?o.getType():Objects.nonNull(o.getTakeShopId())?Constants.ONE:Constants.TWO)
                );
                vo.setCreateTime(o.getCreateTime());
                vo.setRemark(o.getRemark());
                vo.setExpectedTakeTime(o.getExpectedTakeTime());
                vo.setDepositShopName(o.getDepositShopName());
@@ -1570,12 +1580,16 @@
                vo.setDetailList(buildDetailList(details));
                if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) {
                    OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details);
                    vo.setOverdue(overdueInfo.getOverdue());
                    vo.setOverdueDays(overdueInfo.getOverdueDays());
                    vo.setOverdueFee(overdueInfo.getOverdueFee());
                }
                // é€¾æœŸçŠ¶æ€
                fillOverdueStatus(vo, o, details);
//                if (Integer.valueOf(Constants.OrderStatus.arrived.getStatus()).equals(o.getStatus())) {
//                    OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(o, details);
//                    vo.setOverdue(overdueInfo.getOverdue());
//                    vo.setOverdueDays(overdueInfo.getOverdueDays());
//                    vo.setOverdueFee(overdueInfo.getOverdueFee());
//                }
                voList.add(vo);
            }
        }
@@ -1621,7 +1635,7 @@
            }
        }
        if (order == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "核销码无效");
        }
        return buildOrderDetailVO(order, false);
    }
@@ -1724,41 +1738,8 @@
                        .eq(OrdersDetail::getDeleted, Constants.ZERO));
        vo.setDetailList(buildDetailList(details));
        // é€¾æœŸçŠ¶æ€ï¼š0=无逾期 1=存在逾期 2=待支付逾期 3=逾期已支付
        if (Constants.equalsInteger(order.getOverdueStatus(), Constants.TWO)) {
            // è®¢å•标记已支付逾期
            vo.setOverdueStatus(Constants.THREE);
            vo.setOverdue(true);
            vo.setOverdueDays(order.getOverdueDays());
            vo.setOverdueFee(order.getOverdueAmount());
        } else if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) {
            // è®¢å•标记待支付逾期
            vo.setOverdueStatus(Constants.TWO);
            vo.setOverdue(true);
            vo.setOverdueDays(order.getOverdueDays());
            vo.setOverdueFee(order.getOverdueAmount());
        } else if (order.getConfirmArriveTime() != null) {
            // å·²ç¡®è®¤åˆ°åº—,无逾期
            vo.setOverdueStatus(Constants.ZERO);
            vo.setOverdue(false);
            vo.setOverdueDays(0);
            vo.setOverdueFee(0L);
        } else {
            // æœªç¡®è®¤åˆ°åº—,计算实际逾期
            OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details);
            if (overdueInfo.getOverdue() != null && overdueInfo.getOverdue()
                    && overdueInfo.getOverdueFee() != null && overdueInfo.getOverdueFee() > 0) {
                vo.setOverdueStatus(Constants.ONE);
                vo.setOverdue(true);
                vo.setOverdueDays(overdueInfo.getOverdueDays());
                vo.setOverdueFee(overdueInfo.getOverdueFee());
            } else {
                vo.setOverdueStatus(Constants.ZERO);
                vo.setOverdue(false);
                vo.setOverdueDays(0);
                vo.setOverdueFee(0L);
            }
        }
        // é€¾æœŸçŠ¶æ€ï¼š0=未到店未逾期 1=未到店存在逾期 2=已到店未逾期 3=已到店待支付逾期 4=逾期已支付
        fillOverdueStatus(vo, order, details);
        // é€€æ¬¾ä¿¡æ¯ï¼ˆstatus=99取消时返回)
        if (order.getStatus() != null &&
@@ -2638,6 +2619,129 @@
    @Override
    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
    public void verifyOrder(String verifyCode, Integer shopId, List<String> images, String remark) {
        if (StringUtils.isBlank(verifyCode)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码不能为空");
        }
        // å…ˆæŸ¥ä¼šå‘˜æ ¸é”€ç 
        Orders query = new Orders();
        query.setMemberVerifyCode(verifyCode);
        query.setDeleted(Constants.ZERO);
        Orders byMemberCode = findOne(query);
        if (byMemberCode != null) {
            shopVerifyOrder(verifyCode, shopId, images, remark);
        } else {
            driverVerifyOrder(verifyCode, images, remark, shopId);
        }
    }
    @Override
    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
    public void verifyOrderByShopId(Integer orderId, Integer shopId, List<String> images, String remark) {
        if (orderId == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单主键不能为空");
        }
        // æ ¹æ®è®¢å•主键查找订单
        Orders order = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda()
                .eq(Orders::getId, orderId)
                .eq(Orders::getDeleted, Constants.ZERO)
                .last("limit 1"));
        if (order == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "订单不存在");
        }
        // æŸ¥è¯¢é—¨åº—名称用于日志
        String shopName = "";
        ShopInfo shopInfo = shopInfoMapper.selectById(shopId);
        if (shopInfo != null) {
            shopName = shopInfo.getName() != null ? shopInfo.getName() : "";
        }
        Integer status = order.getStatus();
        Date now = new Date();
        if (Constants.equalsInteger(status, Constants.OrderStatus.waitDeposit.getStatus())) {
            // å¾…寄存(1) â†’ å·²å¯„å­˜(2),两种类型通用
            // æ ¡éªŒå½“前门店是否为订单的存件门店
            if (!shopId.equals(order.getDepositShopId())) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销");
            }
            order.setStatus(Constants.OrderStatus.deposited.getStatus());
            order.setDepositTime(now);
            // é‡Šæ”¾å½“前核销码,生成新的核销码供取件时使用
            String verifyCode = order.getMemberVerifyCode();
            if (StringUtils.isNotBlank(verifyCode)) {
                releaseVerifyCode(verifyCode);
            }
            order.setMemberVerifyCode(generateVerifyCode());
            ordersMapper.updateById(order);
            // ä¿å­˜å¯„存图片(obj_type=2 è®¢å•寄存图片,最多3张)
            saveVerifyImages(order.getId(), images, Constants.FileType.ORDER_DEPOSIT.getKey(), shopId);
            // è®°å½•订单日志
            saveShopVerifyLog(order, Constants.OrderLogType.shopDeposit, Constants.OrderLogType.shopDeposit.format(shopName), remark, shopId);
            // é€šçŸ¥ä¼šå‘˜ï¼šé—¨åº—核销成功
            if (Constants.equalsInteger(order.getType(), Constants.ONE)) {
                // å¼‚地寄存 â†’ å¾…抢单
                sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_GRAB, order.getId(),
                        "orderNo", order.getCode());
            } else {
                // å°±åœ°å¯„å­˜ â†’ å¾…取件提醒
                sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(),
                        "orderNo", order.getCode(), "shopName", shopName);
            }
        } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) {
            // å¼‚地寄存 + æ— å–件门店 â†’ æ— æ³•核销(客户自取,无门店操作)
            if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单无取件门店,无法核销");
            }
            // æ ¡éªŒå–件门店与当前登录门店一致
            if (!shopId.equals(order.getTakeShopId())) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销");
            }
            // æ ¡éªŒæ˜¯å¦å·²ç¡®è®¤é¡¾å®¢åˆ°åº—
            if (order.getConfirmArriveTime() == null) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先确认顾客到店");
            }
            // æ ¡éªŒæ˜¯å¦å­˜åœ¨å¾…处理的逾期费用
            if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "存在逾期费用待处理,请先完成逾期费用支付");
            }
            // å¾…取件(5) â†’ å·²å®Œæˆ(7)
            order.setStatus(Constants.OrderStatus.finished.getStatus());
            order.setConfirmArriveTime(now);
            ordersMapper.updateById(order);
            // è®¢å•完成,释放核销码
            String verifyCode = order.getMemberVerifyCode();
            if (StringUtils.isNotBlank(verifyCode)) {
                releaseVerifyCode(verifyCode);
            }
            // ä¿å­˜å‡ºåº“图片(obj_type=13 é—¨åº—出库图片,最多3张)
            saveVerifyImages(order.getId(), images, Constants.FileType.STORE_OUT.getKey(), shopId);
            // ç”Ÿæˆæ”¶ç›Šè®°å½•
            calculateAndSaveOrderFees(order.getId());
            generateRevenueRecords(order.getId());
            // è®°å½•订单日志
            saveShopVerifyLog(order, Constants.OrderLogType.shopTake, Constants.OrderLogType.shopTake.format(shopName), remark, shopId);
            // é€šçŸ¥ä¼šå‘˜ï¼šè®¢å•已完成
            sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.FINISHED, order.getId(),
                    "orderNo", order.getCode());
            // é€šçŸ¥å­˜ä»¶é—¨åº—和取件门店:订单已完成
            String settleDays = operationConfigBiz.getConfig().getSettlementDate();
            notifyBothShops(order, Constants.ShopOrderNotify.FINISHED,
                    "orderNo", order.getCode(),
                    "settleDays", settleDays != null ? settleDays : "7");
            // é€šçŸ¥å¸æœºï¼šè®¢å•已完成
            if (order.getAcceptDriver() != null) {
                sendDriverNotice(order.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, order.getId(),
                        "orderNo", order.getCode(),
                        "settleDays", settleDays != null ? settleDays : "7");
            }
        } else {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "当前订单状态不允许核销");
        }
    }
    @Override
    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
    public void shopVerifyOrder(String verifyCode, Integer shopId, List<String> images, String remark) {
        if (StringUtils.isBlank(verifyCode)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码不能为空");
@@ -2694,6 +2798,14 @@
            // æ ¡éªŒå–件门店与当前登录门店一致
            if (!shopId.equals(order.getTakeShopId())) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单不属于当前门店,无法核销");
            }
            // æ ¡éªŒæ˜¯å¦å·²ç¡®è®¤é¡¾å®¢åˆ°åº—
            if (order.getConfirmArriveTime() == null) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请先确认顾客到店");
            }
            // æ ¡éªŒæ˜¯å¦å­˜åœ¨å¾…处理的逾期费用
            if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "存在逾期费用待处理,请先完成逾期费用支付");
            }
            // å¾…取件(5) â†’ å·²å®Œæˆ(7)
            order.setStatus(Constants.OrderStatus.finished.getStatus());
@@ -3275,6 +3387,62 @@
    }
    /**
    /**
     * å¡«å……逾期状态到 VO(MyOrderVO)
     * overdueStatus: 0=未到店未逾期 1=未到店存在逾期 2=已到店未逾期 3=已到店待支付逾期 4=逾期已支付
     */
    private void fillOverdueStatus(MyOrderVO vo, Orders order, List<OrdersDetail> details) {
        Integer[] result = calcOverdueStatus(order, details);
        vo.setOverdueStatus(result[0]);
        vo.setOverdue(result[1] == 1);
        vo.setOverdueDays(result[2]);
        vo.setOverdueFee(result[3].longValue());
    }
    /**
     * å¡«å……逾期状态到 VO(MyOrderDetailVO)
     */
    private void fillOverdueStatus(MyOrderDetailVO vo, Orders order, List<OrdersDetail> details) {
        Integer[] result = calcOverdueStatus(order, details);
        vo.setOverdueStatus(result[0]);
        vo.setOverdue(result[1] == 1);
        vo.setOverdueDays(result[2]);
        vo.setOverdueFee(result[3].longValue());
    }
    /**
     * è®¡ç®—逾期状态
     * @return [overdueStatus, isOverdue(0/1), overdueDays, overdueFee]
     */
    private Integer[] calcOverdueStatus(Orders order, List<OrdersDetail> details) {
        // 4=逾期已支付(订单 overdueStatus=2)
        if (Constants.equalsInteger(order.getOverdueStatus(), Constants.TWO)) {
            return new Integer[]{4, 1, order.getOverdueDays(), order.getOverdueAmount() != null ? order.getOverdueAmount().intValue() : 0};
        }
        // 3=已到店待支付逾期(订单 overdueStatus=1)
        if (Constants.equalsInteger(order.getOverdueStatus(), Constants.ONE)) {
            return new Integer[]{3, 1, order.getOverdueDays(), order.getOverdueAmount() != null ? order.getOverdueAmount().intValue() : 0};
        }
        // è®¡ç®—实时逾期
        OverdueFeeVO overdueInfo = calculateOverdueFeeInternal(order, details);
        boolean hasOverdue = overdueInfo.getOverdue() != null && overdueInfo.getOverdue()
                && overdueInfo.getOverdueFee() != null && overdueInfo.getOverdueFee() > 0;
        if (order.getConfirmArriveTime() != null) {
            // å·²åˆ°åº—
            int days = hasOverdue ? overdueInfo.getOverdueDays() : 0;
            long fee = hasOverdue ? overdueInfo.getOverdueFee() : 0L;
            return new Integer[]{2, hasOverdue ? 1 : 0, days, (int) fee};
        } else {
            // æœªåˆ°åº—
            if (hasOverdue) {
                return new Integer[]{1, 1, overdueInfo.getOverdueDays(), overdueInfo.getOverdueFee().intValue()};
            } else {
                return new Integer[]{0, 0, 0, 0};
            }
        }
    }
    /**
     * é€¾æœŸè´¹ç”¨å†…部计算(不查库,接受预查询的数据)
     * ä¾›åˆ†é¡µç­‰å·²æŸ¥è¯¢æ˜Žç»†çš„业务场景复用,避免重复查询
     */
server/services/src/main/java/com/doumee/service/business/impl/RevenueServiceImpl.java
@@ -10,14 +10,8 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.RevenueMapper;
import com.doumee.dao.business.WithdrawalOrdersMapper;
import com.doumee.dao.business.MemberMapper;
import com.doumee.dao.business.ShopInfoMapper;
import com.doumee.dao.business.model.Revenue;
import com.doumee.dao.business.model.ShopInfo;
import com.doumee.dao.business.model.Member;
import com.doumee.dao.business.model.WithdrawalOrders;
import com.doumee.dao.business.*;
import com.doumee.dao.business.model.*;
import com.doumee.dao.dto.RevenueQueryDTO;
import com.doumee.dao.vo.RevenueStatisticsVO;
import com.doumee.dao.vo.RevenueSummaryVO;
@@ -26,6 +20,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Driver;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -49,6 +44,9 @@
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private DriverInfoMapper driverInfoMapper;
    @Override
    public Integer create(Revenue revenue) {
@@ -178,11 +176,11 @@
    @Override
    public RevenueStatisticsVO getDriverRevenueStatistics(Integer memberId) {
        Member member = memberMapper.selectById(memberId);
        if (member == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "用户不存在");
        DriverInfo driverInfo = driverInfoMapper.selectById(memberId);
        if (driverInfo == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在");
        }
        return buildRevenueStatistics(memberId, Constants.ONE, member.getAmount());
        return buildRevenueStatistics(memberId, Constants.ONE, driverInfo.getBalance());
    }
    /**
server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java
@@ -1351,4 +1351,31 @@
        }
    }
    @Override
    public void changePassword(Integer shopId, 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(), "密码必须同时包含字母和数字");
        }
        // æŸ¥è¯¢é—¨åº—
        ShopInfo shopInfo = shopInfoMapper.selectById(shopId);
        if (shopInfo == null || Constants.equalsInteger(shopInfo.getDeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        // é‡æ–°ç”Ÿæˆsalt,加密新密码并更新
        String salt = RandomStringUtils.randomAlphabetic(6);
        shopInfo.setPassword(Utils.Secure.encryptPassword(newPassword, salt));
        shopInfo.setSalt(salt);
        shopInfoMapper.updateById(shopInfo);
        // æ¸…除token,强制重新登录
        if (StringUtils.isNotBlank(token)) {
            redisTemplate.delete(token);
        }
    }
}
server/services/src/main/resources/application-dev.yml
@@ -62,6 +62,12 @@
des_pwd: 123456SDFKDJF
jpush:
  appKey:
  masterSecret:
  apnsProduction: false
knife4j:
  enable: true
  basic:
server/services/src/main/resources/application-pro.yml
@@ -1,9 +1,9 @@
spring:
  # æ•°æ®æºé…ç½®
  datasource:
    url: jdbc:mysql://192.168.0.211:3306/gtzxinglijicun?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Doumee@168
    url: jdbc:mysql://rm-bp1qxtf4wy100fur3yo.mysql.rds.aliyuncs.com:3306/gtzxinglijicun?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: gtzxinglijicun
    password: gtzxljc@2026
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  redis:
@@ -54,39 +54,39 @@
  pay:
    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
    v3NotifyUrl: http://xiaopiqiu2.natapp1.cc/web/api/wxPayV3Notify
    v3RefundNotifyUrl: http://xiaopiqiu2.natapp1.cc/web/api/wxRefundV3Notify
    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 #商户支付公钥
    mchId: 1629568742    #商户号
    apiV3Key: NJTLJSTZYXZRGScaiwubuzichanbu666 #apiV3Key
    serialNumer: 25D19D18217F4588841E5CD1AA0D1533DE8AF84A #商户证书序列号
    privateKeyPath: pay/pro/wx/apiclient_key.pem
    v3NotifyUrl: https://llfc.lmpro.cn/nyx_web/web/api/wxPayV3Notify
    v3RefundNotifyUrl: https://llfc.lmpro.cn/nyx_web/web/api/wxRefundV3Notify
    typeId: jinkuai
alipay:
  pay:
    appId: 2021006146626440
    privateKey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0zIy4Ej8yG34uQ8zECWu12INdTWYuvSudhrf1qtUrPx4FO9vDGc8NdPz63M3y+akWh9o8gsl7qQqOoB7o8gYebLTzF2ZP3ByxgkNRGUwZBIi0iL/28eq/2uDCWnqNBDEeFQpfWeRcErC28LCB6JSI7F6owH78LiU8pNO0pVvqwvcLovlVee4UDtLThBegUxkkHXq4EM9yutkfps1ruDiTGFYyTjS8g9BmNJ7rJoRSKTE85Gl8OYp1SuFbyurPEaFLBW9yGHbsqMqegys2PwV6PxZq3WBbFMiuWI5fane+VL2jyVoV36CYPS2GFjq0stuUHZvPL1uYk+bwAAei7a2JAgMBAAECggEBAJMnTX1gNJl28Qt82YPRWx6F292r6nguNfqftMi6Q4hQdgGyh5rTPcfpKSKRZvrVIz+YURMhLBZ/Ln2Ja78ThdFrjxewOvDS6XO830d5vIs8OnweNYgrvHJtFrR5afeuqr+eRnP3OTuLZtNvMWp6v7J2GFFnY7OjZ2Flkn4cfKSkqnLQnZ/oDKA/a40OclHRmaQZcS5YkGZqeR+NssanUDad89IVz7NU0kXTbaXjbGHyJscLr6hM3otdfrYsboJ5XHLOnnpSLptv3I0HSUeHBSdhAbP5Hlot+xOo6EbeougefmT2FZWaDA+kPHgajCOdZHW3v+13Xp+PioRW0IPcsLUCgYEA+11Fqm+tpP351tdkJyW+weTy0/OnvUuSVQP/0/kvzQ84kjfkxdoyTKe6kT8+K5b5dkCQhGRfWgb7/amKEe1loCQsujf7/6aebUgTevrOs96LErMT1fCqId1t/MWgXVFpzo8n2OTks2r0nleHY7C9VZiPIbGBQDbkJChIFRAiRXsCgYEAuCIg2p4RrlOG/i4/r1xKmOIwba9snTBnAB8/bri913xMy055OVF6P46hC6d/J25QNqYGODBBF4kmiBuco+vtuz6C94Uo3h/oYD3jetmwlAnRWjEl9Z3Pkf5cbE+o5KBZmUa+M7BTrBDutzdRDqX2SANvnoDWVF03teY9lcVNL8sCgYEAoFdeEhtNC/tKfKZG58XnCe4Oi+9YJ6LmRD7Z2RCSUl8MOhFXaHIINeekVfSeptWWab1DsoAIZvgflC6quUbS1bVdpqgBopFZa+JXMtJ8OjaSRipfU9BB5npGJ8C0y/Ib6TxeMbfIvz5RrhOtdIUQMWKwotCE3z5khz/+wxjYk7MCgYBrMesgeo9ehl/7T99hboA7GssIv+yiYhBEoOxjwAc9EK8AWNH3zXg20gjtaPh8cxsdhW/vfCAY3I5jBHgfcfU3YcAK6ymMjtTQWpc46MyEkmafdCdeIx45JvSVVZbEaplewzFtlARSEpV2ciytM276I43yn5ynBpGtQrmtnGxAGwKBgQCy8imu84IhC+BivLRYdsQ+hMsqs0nih4wfVPKWr6K64QO6CZ4riL76lppH8UBG5EXtRd6cjBbORgvQtr22OJxFcj8WuZjBvYvvCOsTE0jGMdiyBqx9k0PsLrtlVZPFP4kj9vDSFNIyAgIOiAmYY4kBtGfhQqRcDgZK+mgHY0zMbg==
    appCertPath: foo/pro/appCertPublicKey_2021006146626440.crt
    alipayPublicCertPath: pro/dev/alipayCertPublicKey_RSA2.crt
    rootCertPath: foo/pro/alipayRootCert.crt
    appId: 2021006147660139
    privateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEeqqkZztBHfK+vpyBi6ejgDTHZuZ3yiuXds+lRBbMo/g24F5trH+oLHW0gMhSxihFfQBBIpVBXDsPQK4ZkhDWTaOBktnU1UMRoOEiaaZU6EiWy10ePFUmpdXpkCQEp7rc88OwI90p58S3+L+Ckak60WqNwJBdB5YGBaUunryBA78U4zW1KNY7JvoRnZDcFMQiczikwUzhO7EAi0yVrVpsVsc9s87mcS4uOJKx4qb2E83r9RJ1z30db+cIIZRiLP2oNZBLYzgKpOouE+uIgxhQzlh6cOASNZQulXuUjoT/+Y9w4njfl4TmKIXWcJFKIMc6kMiux9tTncpp0TqRwk1tAgMBAAECggEALkSYtJheusnbpRFr95G0i2sggqh3s1PXihZ/dXKgT9Z5GCsj8X3Cng7CNRxykBN73kk+axhCv56Bhej8Vqcv8ddcnqG/TEBgR+Fzws/QTIRau6/uILWic7RvuE2qPbJl7aw1s9/uL/UVPSGFr7CvgltYVUM4e7/Sk1529JCK4XJfoXP5tKJ3OaXssvaFnCKEU8IGQkjRG+lUZJhAHVtClGHtgrhevgRhy2zre5wp2qSa8d/MqrPruSYS02hn9b5Nl6i2PlUS6dGlJ4lrxYTG22ukYYoxAPNPS7gnvmveXonWP7b5tPhKRpZjnoySojz3WECUlhz/v8wM1cDrpq+GQQKBgQDsc7y2rlx4f77a7ORfb5/qWHCOJs1cIzggj0kJ7TgFGe71kbCQ5nywD/Fe5V9OwbW+DCxOME+SrrHeiK4axWiu5si/1JlurJoxNy+4k4ywk3ZA3Nv2aBhlPqfkwDhJ0z7Mgsq2c/YgnVddmSvKZoC39wA77ovks4GDxaBOt8N7PQKBgQDUuPGgzkwcgb60UdaxfMbacrPsW26vDxaE4ceuXo2m8KDiCIqkF2y9r6AdWMTgGGSJwOsk7+FP+21VdRivCg9HcOLWngveUc6xDIuqKHVpemMo3SdCF4Wqf96rRc3VOBr5cfIdWxeorZf5umMyKnIAjAFETOOrK7eLTTmjyLD98QKBgB82S+Plcklpu3zUpnS+nGJn2Du7fYI7F+6cW2zXBn0N5lA+Mgt+kVkAUcFQD9uqkF4M51BO6kIXk10nt6vLAT2NM1S3MKW+XQBAI6l+uKSaYpK/VL3bEdVThwAYK5X7L5/5Z97bwdKeUmkFjhVCoJ0oGrzOiWLgGymUzct2UHSVAoGBAMb+7Cs+Ub0pMrmFBY6r52pbey1Uq0pglvRgMmhQU7sjx50r2GaA81zPer15WVM5/nNPYaoALYqg7jrPe/PjOT/fvpR+7SNg7DZ8QftANfYiY7jKifst/gDt9ePLPS6FedZ4XcJQgOVu34jicAFx64vPbS/zrddm4iEScSVijRBBAoGAXCheERsx8+n16Us/DttXFUa1nc7+D8WR6buM1QMZgQCVF2qp3XtM+FusCKL4+q1+dtag8svLjJFp9QbaAXqX8Zk7rn8wUHbDloPTPy9XWgrPowyL9MPU+e/Rq8Hr6TWPDBd4TU64YzIEfBQYpJXfZbXhVYmK3o7xHXKB1x4vvEM=
    appCertPath: pay/pro/appCertPublicKey.crt
    alipayPublicCertPath: pay/pro/alipayCertPublicKey_RSA2.crt
    rootCertPath: pay/pro/alipayRootCert.crt
upload:
  type: blob
qiwei:
  serviceurl: https://wecom-qyapi.unilever-china.com/
  type: ftp
# è…¾è®¯åœ°å›¾apikey
tencent_key: WE3BZ-HN6WS-ONDOH-62QCV-MNL6F-5NFNE
tencent_key:
# é«˜å¾·åœ°å›¾apikey
geocode_map_key:
geocode_map_key: 9a6c1f0eff2e5aa91989ca9d4c21e262
qiwei:
  serviceurl: https://qyapi.weixin.qq.com
aes:
  encrypt:
    open: true # æ˜¯å¦å¼€å¯åР坆 true  or  false
    showLog: true # æ˜¯å¦æ‰“印加解密log true  or  false
    publicKey: mN4Yn8Or8r7SH1w3 # AES密钥
    privateKey:  # RSA私钥
    time: 600000
server/web/src/main/java/com/doumee/api/web/AccountApi.java
@@ -1,7 +1,9 @@
package com.doumee.api.web;
import com.doumee.config.jwt.JwtTokenUtil;
import com.doumee.core.annotation.LoginDriverRequired;
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.constants.Constants;
import com.doumee.core.model.ApiResponse;
@@ -92,19 +94,30 @@
    }
    @LoginRequired
    @LoginShopRequired
    @ApiOperation(value = "门店退出登录", notes = "小程序端")
    @GetMapping("/logOutShop")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse logOutShop() {
        String token = this.getRequest().getHeader(JwtTokenUtil.HEADER_KEY);
        String token = this.getRequest().getHeader(JwtTokenUtil.SHOP_HEADER_KEY);
        memberService.logOut(token,getShopId(), Constants.TWO);
        return  ApiResponse.success("操作成功");
    }
    @LoginDriverRequired
    @ApiOperation(value = "司机退出登录", notes = "小程序端")
    @GetMapping("/logOutDriver")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse logOutDriver() {
        String token = this.getRequest().getHeader(JwtTokenUtil.HEADER_KEY);
        memberService.logOut(token,getDriverId(), Constants.ONE);
        return  ApiResponse.success("操作成功");
    }
    @LoginRequired
    @ApiOperation(value = "用户注销", notes = "小程序端")
    @GetMapping("/logOff")
server/web/src/main/java/com/doumee/api/web/ConfigApi.java
@@ -1,5 +1,6 @@
package com.doumee.api.web;
import com.doumee.core.annotation.LoginDriverRequired;
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.annotation.trace.Trace;
@@ -184,7 +185,7 @@
        return ApiResponse.success("查询成功", noticeService.findPage(pageWrap));
    }
    @LoginRequired
    @LoginShopRequired
    @ApiOperation(value = "门店标记全部已读", notes = "标记当前用户所有未读通知为已读")
    @PostMapping("/shopReadAllNotice")
    @ApiImplicitParams({
@@ -219,4 +220,32 @@
    }
    @LoginDriverRequired
    @ApiOperation(value = "司机通知消息分页", notes = "未读优先,时间倒序")
    @PostMapping("/driverNoticePage")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse<PageData<Notice>> driverNoticePage(@RequestBody PageWrap<Notice> pageWrap) {
        if (pageWrap.getModel() == null) {
            pageWrap.setModel(new Notice());
        }
        pageWrap.getModel().setUserId(this.getDriverId());
        pageWrap.getModel().setUserType(Constants.ONE);
        return ApiResponse.success("查询成功", noticeService.findPage(pageWrap));
    }
    @LoginDriverRequired
    @ApiOperation(value = "司机标记全部已读", notes = "标记当前用户所有未读通知为已读")
    @PostMapping("/driverReadAllNotice")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse driverReadAllNotice() {
        noticeService.readAllNotice(Constants.ONE, this.getDriverId());
        return ApiResponse.success("操作成功");
    }
}
server/web/src/main/java/com/doumee/api/web/DriverInfoApi.java
@@ -3,6 +3,7 @@
import com.doumee.core.annotation.LoginDriverRequired;
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.config.jwt.JwtTokenUtil;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
@@ -29,6 +30,7 @@
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
 * å¸æœºéªŒè¯ç ç™»å½•接口
@@ -133,6 +135,17 @@
    @LoginDriverRequired
    @Trace
    @ApiOperation(value = "司机累计统计", notes = "累计佣金、待结算佣金、订单总数、钱包余额")
    @GetMapping("/stats")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse<com.doumee.dao.vo.DriverStatsVO> stats() {
        return ApiResponse.success("操作成功", driverInfoService.getDriverStats(this.getDriverId()));
    }
    @LoginDriverRequired
    @Trace
    @ApiOperation(value = "司机抢单大厅", notes = "分页查询可抢的异地寄存订单")
    @PostMapping("/grabOrderHall")
    @ApiImplicitParams({
@@ -215,4 +228,28 @@
        return ApiResponse.success("操作成功");
    }
    @LoginDriverRequired
    @Trace
    @ApiOperation(value = "司机修改密码", notes = "新密码必须同时包含字母和数字,修改成功后需重新登录")
    @GetMapping("/changePassword")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse changePassword(@RequestParam String newPassword) {
        String token = this.getRequest().getHeader(JwtTokenUtil.HEADER_KEY);
        driverInfoService.changePassword(this.getDriverId(), newPassword, token);
        return ApiResponse.success("密码修改成功,请重新登录");
    }
    @LoginDriverRequired
    @Trace
    @ApiOperation(value = "进行中订单数量", notes = "返回已抢单和派送中的订单数量")
    @GetMapping("/activeOrderCount")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse<Map<String, Integer>> activeOrderCount() {
        return ApiResponse.success("操作成功", driverInfoService.getActiveOrderCount(this.getDriverId()));
    }
}
server/web/src/main/java/com/doumee/api/web/OrdersApi.java
@@ -3,6 +3,7 @@
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.constants.Constants;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
@@ -10,7 +11,6 @@
import com.doumee.dao.dto.CommentOrderDTO;
import com.doumee.dao.dto.ConfirmArriveDTO;
import com.doumee.dao.dto.CreateOrderDTO;
import com.doumee.dao.dto.DriverVerifyDTO;
import com.doumee.dao.dto.ShopVerifyDTO;
import com.doumee.dao.dto.StoreOutDTO;
import com.doumee.dao.dto.MyOrderDTO;
@@ -147,24 +147,13 @@
    }
    @LoginShopRequired
    @ApiOperation(value = "门店核销收件", notes = "门店通过核销码确认收件/取件")
    @ApiOperation(value = "门店核销", notes = "门店通过订单主键确认寄存/取件")
    @PostMapping("/shopVerify")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "门店token值", required = true)
    })
    public ApiResponse shopVerify(@RequestBody @Validated ShopVerifyDTO dto) {
        ordersService.shopVerifyOrder(dto.getVerifyCode(), getShopId(), dto.getImages(), dto.getRemark());
        return ApiResponse.success("核销成功");
    }
    @LoginShopRequired
    @ApiOperation(value = "核销司机码", notes = "异地寄存且有取件门店的订单,通过司机核销码确认到店")
    @PostMapping("/driverVerify")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse driverVerify(@RequestBody @Validated DriverVerifyDTO dto) {
        ordersService.driverVerifyOrder(dto.getVerifyCode(), dto.getImages(), dto.getRemark(), getShopId());
        ordersService.verifyOrderByShopId(dto.getOrderId(), getShopId(), dto.getImages(), dto.getRemark());
        return ApiResponse.success("核销成功");
    }
@@ -178,7 +167,9 @@
    })
    public ApiResponse<MyOrderDetailVO> shopDetail(@RequestParam(required = false) Integer orderId,
                                                    @RequestParam(required = false) String verifyCode) {
        return ApiResponse.success("查询成功", ordersService.findShopOrderDetail(orderId, verifyCode));
        MyOrderDetailVO myOrderDetailVO = ordersService.findShopOrderDetail(orderId, verifyCode);
        myOrderDetailVO.setMemberVerifyCode(null);
        return ApiResponse.success("查询成功", myOrderDetailVO);
    }
    @LoginShopRequired
server/web/src/main/java/com/doumee/api/web/RevenueApi.java
@@ -1,5 +1,6 @@
package com.doumee.api.web;
import com.doumee.core.annotation.LoginDriverRequired;
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.annotation.trace.Trace;
@@ -29,24 +30,24 @@
    @Autowired
    private RevenueService revenueService;
    @LoginRequired
    @LoginDriverRequired
    @ApiOperation(value = "司机流水分页", notes = "小程序端")
    @PostMapping("/driverPage")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<PageData<Revenue>> driverPage(@RequestBody @Validated PageWrap<RevenueQueryDTO> pageWrap) {
        return ApiResponse.success("查询成功", revenueService.findDriverRevenuePage(pageWrap, getMemberId()));
        return ApiResponse.success("查询成功", revenueService.findDriverRevenuePage(pageWrap, getDriverId()));
    }
    @LoginRequired
    @LoginDriverRequired
    @ApiOperation(value = "司机流水收支统计", notes = "根据查询条件统计收入与支出")
    @PostMapping("/driverSummary")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<RevenueSummaryVO> driverSummary(@RequestBody RevenueQueryDTO queryDTO) {
        return ApiResponse.success("查询成功", revenueService.getDriverRevenueSummary(queryDTO, getMemberId()));
        return ApiResponse.success("查询成功", revenueService.getDriverRevenueSummary(queryDTO, getDriverId()));
    }
    @LoginShopRequired
server/web/src/main/java/com/doumee/api/web/ShopInfoApi.java
@@ -2,6 +2,8 @@
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.config.jwt.JwtTokenUtil;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
@@ -116,4 +118,17 @@
        return ApiResponse.success("操作成功", ordersService.payShopDeposit(getMemberId()));
    }
    @LoginShopRequired
    @Trace
    @ApiOperation(value = "门店修改密码", notes = "新密码必须同时包含字母和数字,修改成功后需重新登录")
    @PostMapping("/changePassword")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "门店token值", required = true),
    })
    public ApiResponse changePassword(@RequestParam String newPassword) {
        String token = this.getRequest().getHeader(JwtTokenUtil.HEADER_KEY);
        shopInfoService.changePassword(this.getShopId(), newPassword, token);
        return ApiResponse.success("密码修改成功,请重新登录");
    }
}
server/web/src/main/java/com/doumee/api/web/WalletApi.java
@@ -1,5 +1,6 @@
package com.doumee.api.web;
import com.doumee.core.annotation.LoginDriverRequired;
import com.doumee.core.annotation.LoginRequired;
import com.doumee.core.annotation.LoginShopRequired;
import com.doumee.core.model.ApiResponse;
@@ -40,14 +41,14 @@
    @Autowired
    private RevenueService revenueService;
    @LoginRequired
    @LoginDriverRequired
    @ApiOperation(value = "司机提现申请", notes = "小程序端")
    @PostMapping("/driverApply")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse driverApply(@RequestBody @Validated WithdrawalDTO dto) {
        withdrawalOrdersService.applyDriverWithdrawal(dto, getMemberId());
        withdrawalOrdersService.applyDriverWithdrawal(dto, getDriverId());
        return ApiResponse.success("提现申请已提交");
    }
@@ -72,24 +73,36 @@
        return ApiResponse.success("查询成功", revenueService.getShopRevenueStatistics(getShopId()));
    }
    @LoginRequired
    @LoginDriverRequired
    @ApiOperation(value = "司机收益统计", notes = "当前登录司机的收益/提现统计")
    @GetMapping("/driverStatistics")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true)
    })
    public ApiResponse<RevenueStatisticsVO> driverStatistics() {
        return ApiResponse.success("查询成功", revenueService.getDriverRevenueStatistics(getMemberId()));
        return ApiResponse.success("查询成功", revenueService.getDriverRevenueStatistics(getDriverId()));
    }
    @LoginRequired
    @ApiOperation(value = "提现详情", notes = "根据提现主键查询详情(含审批人信息)")
    @GetMapping("/detail/{id}")
    @LoginShopRequired
    @ApiOperation(value = "门店提现详情", notes = "根据提现主键查询详情(含审批人信息)")
    @GetMapping("/shopDetail/{id}")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "id", value = "提现记录主键", required = true)
    })
    public ApiResponse<WithdrawalOrders> detail(@PathVariable Integer id) {
    public ApiResponse<WithdrawalOrders> shopDetail(@PathVariable Integer id) {
        return ApiResponse.success("查询成功", withdrawalOrdersService.findById(id));
    }
    @LoginDriverRequired
    @ApiOperation(value = "司机提现详情", notes = "根据提现主键查询详情(含审批人信息)")
    @GetMapping("/driverDetail/{id}")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "path", dataType = "Integer", name = "id", value = "提现记录主键", required = true)
    })
    public ApiResponse<WithdrawalOrders> driverDetail(@PathVariable Integer id) {
        return ApiResponse.success("查询成功", withdrawalOrdersService.findById(id));
    }