rk
2 天以前 467fe3b3ec6aa9d449b094bdd9df4611323d88d1
server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -18,11 +18,8 @@
 */
public class Constants {
    public static final String HWY_OBS ="HWY_OBS" ;
    public static final String HWY_OBS_ACCESSID ="HWY_OBS_ACCESSID" ;
    public static final String HWY_OBS_ACCESSKEY ="HWY_OBS_ACCESSKEY" ;
    public static final String HWY_OBS_ENDPOINT ="HWY_OBS_ENDPOINT" ;
    public static final String HWY_OBS_BUCKET ="HWY_OBS_BUCKET" ;
    public static final String OSS ="OSS" ;
    public static final String RESOURCE_PATH ="RESOURCE_PATH" ;
    public static final String QYWX_CORPID = "QYWX_CORPID";
    public static final String QYWX_SECRET = "QYWX_SECRET";
@@ -53,6 +50,27 @@
    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";
    public static final String ACCESS_KEY = "ACCESS_KEY";
    public static final String ENDPOINT = "ENDPOINT";
    public static final String QYWX = "QYWX";
    public static final  Integer ONE = 1;
@@ -62,10 +80,27 @@
    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";
    public static final String SHOP_FILES = "SHOP_FILES";
    public static final String DRIVER_FILES = "DRIVER_FILES";
    public static final String BANNER_FILES = "BANNER_FILES";
    public static final String ORDERS_FILES = "ORDERS_FILES";
    // 运营配置
    public static final String OPERATION_CONFIG = "OPERATION_CONFIG";
    public static final String OP_DRIVER_DAILY_CANCEL_LIMIT = "DRIVER_DAILY_CANCEL_LIMIT";
    public static final String OP_UNPICKED_DISCOUNT = "UNPICKED_DISCOUNT";
    public static final String OP_SETTLEMENT_DATE = "SETTLEMENT_DATE";
    public static final String OP_URGENT_COEFFICIENT = "URGENT_COEFFICIENT";
    public static final String OP_AUTO_CANCEL_TIME = "AUTO_CANCEL_TIME";
    public static final String OP_INSURANCE_RATE = "INSURANCE_RATE";
    public static final String OP_ORDER_ACCEPT_LIMIT = "ORDER_ACCEPT_LIMIT";
    public static final String OP_AUTO_CONFIRM_RECEIPT = "AUTO_CONFIRM_RECEIPT";
    public static final String OP_NO_GRAB_NOTIFY_TIME = "NO_GRAB_NOTIFY_TIME";
    public static final String OP_NO_GRAB_NOTIFY_USERS = "NO_GRAB_NOTIFY_USERS";
    public static boolean WORKORDER_SHE_EMAIL_SENDING = false;
    public static  boolean DEALING_COMPANY_SYNC = false ;
    public static  boolean DEALING_MEMBER_SYNC = false ;
@@ -73,6 +108,12 @@
    public static final String WORKORDER_LOG_FILE_PATH ="WORKORDER_LOG_FILE_PATH" ;
    public static final String REDIS_TOKEN_KEY = "token_";
    public static final String REDIS_VERIFY_CODE_KEY = "verify_code_";
    public final static String GOODS_ORDER_CREATE_LOCK = "goods:order:create:lock:";
    public static final String SUCCESS = "SUCCESS";
    public static final String FAIL = "FAIL";
@@ -247,117 +288,6 @@
    }
    /**
     * 文件附件类型
     */
    public interface multiFileType{
        //0问题上报 1跌绊滑上报 2跌绊滑处理 3分配物业主管 4分配处理人 5DCA风险上报 6DCA风险处理 7DCA问题工单图片
//        int sheUpload = 0;
//        int dbhUpload = 1;
//        int dbhDeal = 2;
//        int dbhAllocation = 3;
//        int dbhDealUser = 4;
//        int dcaUpload = 5;
//        int dcaDeal = 6;
//        int dcaWorkOrder= 7;
        //0工单上报 1工单处理 2工单转交
        int  upload = 0;
        int deal = 1;
        int passOn = 2;
    }
    public enum WorkOrderStatus{
        waitConfirm( 0, "待分配WTS","{title}上报","","待分配WTS" ),
        waitAllocation(1, "待分配任务","待分配任务","","待分配任务"),
        waitDeal(2, "待处理","待处理","","待工程师处理"),
        sheClose(3, "已解决","SHE已关闭","","SHE已关闭"),
        wtsClose(4, "已解决","WTS已关闭","","WTS已关闭"),
        close(5, "已解决","已解决","","工程师关闭"),
        urge (6, "催促","","","")
        ;
        private int status;
        private String statusInfo;
        private String statusName;
        private String logTitle;
        private String noticeContent;
        // 构造方法
        WorkOrderStatus(int status, String statusInfo,String logTitle,String noticeContent,String statusName ) {
            this.status = status;
            this.statusInfo = statusInfo;
            this.logTitle = logTitle;
            this.noticeContent = noticeContent;
            this.statusName = statusName;
        }
        public static String getName(int index) {
            for (WorkOrderStatus c : WorkOrderStatus.values()) {
                if (c.getKey() == index) {
                    return c.statusInfo;
                }
            }
            return null;
        }
        public static String getStatusName(int index) {
            for (WorkOrderStatus c : WorkOrderStatus.values()) {
                if (c.getKey() == index) {
                    return c.statusName;
                }
            }
            return null;
        }
        public int getKey() {
            return status;
        }
        public void setKey(int key) {
            this.status = status;
        }
        public int getStatus() {
            return status;
        }
        public void setStatus(int status) {
            this.status = status;
        }
        public String getStatusName() {
            return statusName;
        }
        public void setStatusName(String statusName) {
            this.statusName = statusName;
        }
        public String getStatusInfo() {
            return statusInfo;
        }
        public void setStatusInfo(String statusInfo) {
            this.statusInfo = statusInfo;
        }
        public String getLogTitle() {
            return logTitle;
        }
        public void setLogTitle(String logTitle) {
            this.logTitle = logTitle;
        }
        public String getNoticeContent() {
            return noticeContent;
        }
        public void setNoticeContent(String noticeContent) {
            this.noticeContent = noticeContent;
        }
    }
    /**
     * 附件类型(对应 multifile.objType)
@@ -368,7 +298,7 @@
        OTHER_MATERIAL(0, "门店其他材料"),
        STORE_INTERIOR(1, "门店内部照片"),
        ORDER_DEPOSIT(2, "订单寄存图片"),
        ORDER_TAKE(3, "订单取件图片"),
        ORDER_TAKE(3, "门店入库图片"),
        DRIVER_TAKE(4, "司机取件图片"),
        DRIVER_DONE(5, "司机完成图片"),
        DRIVER_CAR(6, "司机实名认证车辆照片"),
@@ -377,15 +307,343 @@
        STORE_FRONT(9, "门店门头照"),
        SOCIAL_SECURITY(10, "社保缴纳证明"),
        LABOR_CONTRACT(11, "有效劳动合同"),
        ORDER_FILE(12,"下单图片"),
        STORE_OUT(13,"门店出库图片"),
        REFUND_TAKE(14,"退款取件图片"),
        COMMENT_ATTACH(15,"评价附件图片")
        ;
        private final int key;
        private final String name;
    }
    @Getter
    @AllArgsConstructor
    public enum OrderLogType {
        urgent(2, "平台加急", "平台加急,奖励金【{param}】元"),
        assignDriver(3, "平台指派", "平台指派司机【{param}】接单,奖励金【{param1}】元"),
        memberCancel(4, "会员取消订单", "{param}"),
        driverCancel(4, "司机取消订单", "{param}"),
        systemCancel(4, "系统自动取消", "{param}"),
        systemComplete(4, "系统自动完成", "{param}"),
        memberCancelToConvert(4, "会员取消异地寄存", "{param}"),
        shopDeposit(8, "门店确认寄存", "门店【{param}】确认寄存"),
        shopTake(9, "门店确认取件", "门店【{param}】确认取件,订单完成"),
        shopOutStock(10, "门店确认出库", "{param}"),
        shopConfirmArriveOverdue(5, "确认顾客到店(逾期)", "{param}"),
        shopConfirmArrive(5, "确认顾客到店", "{param}"),
        driverGrab(6, "司机抢单", "司机【{param}】抢单成功"),
        driverPickup(6, "司机完成取件", "司机【{param}】完成取件,开始派送"),
        driverDeliver(7, "司机确认送达", "{param}"),
        ;
        private final int status;
        private final String title;
        private final String statusInfo;
    public  static String getIpAddr() {
        public String format(String... params) {
            String result = statusInfo;
            if (params != null && params.length > 0) {
                result = result.replace("{param}", params[0] != null ? params[0] : "");
            }
            for (int i = 1; i < params.length; i++) {
                result = result.replace("{param" + i + "}", params[i] != null ? params[i] : "");
            }
            return result;
        }
    }
    /**
     * 订单支付类型
     */
    @Getter
    @AllArgsConstructor
    public enum OrdersAttach {
        STORAGE_ORDER("storageOrder", "寄存订单"),
        SHOP_DEPOSIT("shopDeposit", "店铺押金订单"),
        DRIVER_DEPOSIT("driverDeposit", "司机押金订单"),
        OVERDUE_FEE("overdueFee", "订单逾期费用")
        ;
        private final String key;
        private final String name;
    }
    /**
     * 订单状态(就地/异地统一)
     * 就地寄存: 0→1→2→3→(6)→7 / 96~99
     * 异地寄存: 0→1→2→3→4→5→(6)→7 / 96~99
     */
    @Getter
    @AllArgsConstructor
    public enum OrderStatus {
        waitPay(0, "待支付"),
        waitDeposit(1, "待寄存"),
        deposited(2, "已寄存"),
        accepted(3, "已接单"),
        delivering(4, "派送中"),
        arrived(5, "已到店/已送达/待取件"),
        overdue(6, "存在逾期"), //弃用
        finished(7, "已完成"),
        cancelled(99, "已取消")
        ;
        private final int status;
        private final String desc;
        public int getKey() { return status; }
        public String getValue() { return desc; }
        public static OrderStatus getByKey(int index) {
            for (OrderStatus c : OrderStatus.values()) {
                if (c.getKey() == index) {
                    return c;
                }
            }
            return null;
        }
        public static String getDescByKey(int index,int type) {
            for (OrderStatus c : OrderStatus.values()) {
                if (c.getKey() == index) {
                    if (c.getKey() == 5) {
                        if(Constants.equalsInteger(type,Constants.ZERO)){
                            return "待取件";
                        }else{
                            return "已送达";
                        }
                    }
                    return c.getValue();
                }
            }
            return "";
        }
    }
    /**
     * 会员端合并订单状态(用于分页筛选)
     */
    @Getter
    @AllArgsConstructor
    public enum OrderCombinedStatus {
        waitPay(0, "待支付", new int[]{OrderStatus.waitPay.status}),
        waitDeposit(1, "待核验", new int[]{OrderStatus.waitDeposit.status}),
        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}),
        home(6, "首页查询", new int[]{OrderStatus.waitPay.status, OrderStatus.waitDeposit.status, OrderStatus.deposited.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;
        private final int[] statuses;
        public static OrderCombinedStatus getByKey(int key) {
            for (OrderCombinedStatus c : OrderCombinedStatus.values()) {
                if (c.getKey() == key) {
                    return c;
                }
            }
            return null;
        }
    }
    /**
     * 首页订单状态提示枚举
     * status: 订单状态值
     * desc: 状态描述
     * tipTemplate: 提示文案模板,占位符用 {xxx} 表示
     */
    @Getter
    @AllArgsConstructor
    public enum OrderStatusTip {
        waitPay(0, "待支付", "请在{timeout}分钟内完成支付,超时订单将自动取消"),
        waitDeposit(1, "待寄存", "订单已支付,请前往门店寄存"),
        deposited(2, "已寄存", null), // 就地/异地文案不同,动态处理
        accepted(3, "已接单", "已有司机抢单,正前往取件地点"),
        delivering(4, "派送中", "司机已取件,正运往目的地"),
        arrived(5, "待取件", null), // 就地/异地/有无取件门店文案不同,动态处理
        ;
        private final int status;
        private final String desc;
        private final String tipTemplate;
        public static OrderStatusTip getByStatus(int status) {
            for (OrderStatusTip t : OrderStatusTip.values()) {
                if (t.status == status) {
                    return t;
                }
            }
            return null;
        }
    }
    /**
     * 订单站内信通知枚举
     * title: 通知标题
     * content: 通知文案模板,占位符用 {xxx} 表示
     */
    @Getter
    @AllArgsConstructor
    public enum MemberOrderNotify {
        WAIT_PAY("waitPay", "订单待支付", "您的行李订单:{orderNo}已创建,请在{timeout}分钟内完成支付,超时将自动取消"),
        WAIT_VERIFY("waitVerify", "订单待核验", "您的行李订单:{orderNo}已提交,等待门店核验物品信息,存件码{storeCode}"),
        WAIT_GRAB("waitGrab", "订单待抢单", "您的行李订单:{orderNo}已核验,正在为您安排取件司机"),
        WAIT_PICKUP_REMIND("waitPickupRemind", "订单待取件", "您的行李订单:{orderNo}已寄存,请记得在预约取件时间凭取件码前往{shopName}门店取回"),
        WAIT_PICKUP_GRABBED("waitPickupGrabbed", "订单已抢单", "您的行李订单:{orderNo}已有司机{driverName}抢单,正前往取件地点"),
        DELIVERING("delivering", "订单配送中", "您的行李订单:{orderNo}已由司机{driverName}取件,正运往目的地"),
        ARRIVED_NO_SHOP("arrivedNoShop", "订单已送达", "您的行李订单:{orderNo}已送达{destination},请及时确认收货"),
        ARRIVED_HAS_SHOP("arrivedHasShop", "订单已送达", "您的行李订单:{orderNo}已送达{destination},请及时取件,取件码{pickupCode}"),
        FINISHED("finished", "订单已完成", "您的行李订单:{orderNo}已完成,感谢您的支持,请对本次服务做出评价"),
        EVALUATED("evaluated", "订单已评价", "您的行李订单:{orderNo}评价已提交,感谢您的用心评价,祝您出行顺利,旅途愉快!"),
        CANCELLED("cancelled", "订单已取消", "您的行李订单:{orderNo}已取消,感谢您的支持,欢迎下次再会!"),
        DRIVER_CHANGED("driverChanged", "司机变更提醒", "您的行李订单:{orderNo}原司机已取消,系统正在为您匹配新司机,请留意通知。"),
        REFUNDING("refunding", "订单退款中", "您的行李订单:{orderNo}退款申请已提交,平台会将尽快为您处理退款"),
        REFUNDED("refunded", "订单已退款", "您的行李订单:{orderNo}退款已完成,金额{amount}元将原路退回,请注意查收")
        ;
        private final String key;
        private final String title;
        private final String content;
        /**
         * 格式化通知内容
         * @param params 键值对,如 "orderNo","123" 交替传入
         */
        public String format(String... params) {
            String result = this.content;
            for (int i = 0; i < params.length - 1; i += 2) {
                result = result.replace("{" + params[i] + "}", params[i + 1]);
            }
            return result;
        }
    }
    /**
     * 门店订单站内信通知枚举
     * title: 通知标题
     * content: 通知文案模板,占位符用 {xxx} 表示
     */
    @Getter
    @AllArgsConstructor
    public enum ShopOrderNotify {
        WAIT_VERIFY("waitVerify", "订单待核验", "新行李订单:{orderNo}已支付,请尽快核验用户物品信息"),
        WAIT_PICKUP("waitPickup", "订单待取件", "行李订单:{orderNo}已抢单,等待{name}取件"),
        REFUNDING("refunding", "订单退款中", "行李订单:{orderNo}用户提交退款申请,请知悉"),
        DELIVERING("delivering", "订单配送中", "行李订单:{orderNo}已由司机{driverName}取件,正在配送中"),
        ARRIVED("arrived", "订单已送达", "行李订单:{orderNo}已送达{destination},请联系用户确认签收"),
        FINISHED("finished", "订单已完成", "行李订单:{orderNo}已完成,相关订单结算会在{settleDays}个工作日内完成"),
        EVALUATED("evaluated", "订单已评价", "行李订单:{orderNo}用户已完成评价,可查看评价内容"),
        SETTLED("settled", "订单结算", "行李订单:{orderNo}平台已完成结算,金额为{amount}元,请注意查收。")
        ;
        private final String key;
        private final String title;
        private final String content;
        /**
         * 格式化通知内容
         * @param params 键值对,如 "orderNo","123" 交替传入
         */
        public String format(String... params) {
            String result = this.content;
            for (int i = 0; i < params.length - 1; i += 2) {
                result = result.replace("{" + params[i] + "}", params[i + 1]);
            }
            return result;
        }
    }
    /**
     * 司机订单站内信通知枚举
     * title: 通知标题
     * content: 通知文案模板,占位符用 {xxx} 表示
     */
    @Getter
    @AllArgsConstructor
    public enum DriverOrderNotify {
        WAIT_DELIVER("waitDeliver", "订单待配送", "您已抢单成功,行李订单:{orderNo}请按时到{shopName}取件"),
        DELIVERING("delivering", "订单配送中", "行李订单:{orderNo}已取件,正在配送中,请按时送达"),
        ARRIVED("arrived", "订单已送达", "行李订单:{orderNo}已送达{destination},请联系用户确认签收"),
        FINISHED("finished", "订单已完成", "行李订单:{orderNo}已完成,相关订单结算会在{settleDays}个工作日内结算"),
        EVALUATED("evaluated", "订单已评价", "行李订单:{orderNo}用户已完成评价,可前往订单查看评价内容"),
        REFUNDING("refunding", "订单退款中", "行李订单:{orderNo}用户已提交退款申请,该订单任务已取消,请勿前往。"),
        SETTLED("settled", "订单已结算", "行李订单:{orderNo}平台已完成结算,金额为{amount}元,请注意查收。"),
        CANCELLED("cancelled", "订单取消成功", "行李订单:{orderNo}已帮您取消,您今日还可主动取消{cancelLimit}次订单,请合理安排接单。")
        ;
        private final String key;
        private final String title;
        private final String content;
        /**
         * 格式化通知内容
         * @param params 键值对,如 "orderNo","123" 交替传入
         */
        public String format(String... params) {
            String result = this.content;
            for (int i = 0; i < params.length - 1; i += 2) {
                result = result.replace("{" + params[i] + "}", params[i + 1]);
            }
            return result;
        }
    }
    /**
     * 短信通知模板枚举
     * templateCode: 阿里云短信模板Code
     * content: 短信文案模板,占位符用 {xxx} 表示
     */
    @Getter
    @AllArgsConstructor
    public enum SmsNotify {
        PLATFORM_WAIT_GRAB("SMS_505790009", "平台端-待抢单", "您好,订单:{orderNo}已超过{time}分钟无司机抢单,请尽快加急派单,避免客户过久等待。"),
        SHOP_REFUNDING("SMS_505900008", "门店端-退款中", "行李订单:{orderNo}客户已提交退款申请,请尽快处理。"),
        SHOP_WAIT_VERIFY("SMS_505925004", "门店端-待核验", "新行李订单:{orderNo}客户已支付,请尽快核验用户物品信息。"),
        DRIVER_REFUNDING("SMS_505795005", "司机端-退款中", "行李订单:{orderNo}用户已提交退款申请,该订单任务已取消,请勿前往。"),
        DRIVER_WAIT_PICKUP("SMS_505650038", "司机端-待取件", "您已抢单成功,订单{orderNo},请按时到{address}取件。"),
        MEMBER_CANCELLED("SMS_505605028", "会员端-已取消", "您的行李订单:{orderNo}已取消,感谢您的支持,欢迎下次再会。"),
        MEMBER_REFUNDED("SMS_505920002", "会员端-已退款", "您的行李订单:{orderNo}退款已完成,金额{money}元将原路退回,请注意查收。"),
        MEMBER_ARRIVED("SMS_505875004", "会员端-已送达", "您的行李订单:{orderNo}已送到{address},请及时取件,取件码:{code}。"),
        MEMBER_DELIVERING("SMS_505935002", "会员端-配送中", "您的行李订单:{orderNo}已由司机{name}取件,正运往目的地。"),
        VERIFY_CODE("SMS_333770877", "验证码短信", "您的验证码为:{code},请勿泄露于他人!"),
        DRIVER_AUTH_REJECTED("SMS_505790115", "司机端-司机认证被拒绝", "尊敬的{driver},很遗憾,您的司机认证未通过审核。原因:{reason}。您可修改资料后重新提交。"),
        DRIVER_AUTH_APPROVED("SMS_505885083", "司机端-司机认证通过", "尊敬的{driver},恭喜您已通过平台司机认证审核。您可登录司机端APP开始接单,配送过程中请注意安全,祝您接单顺利!"),
        DRIVER_URGENT_DISPATCH("SMS_505885082", "司机端-加急派单", "您好,您有一个新的行李订单(编号:{orderNo})。起点:{address1},终点:{address2},配送费{money1}元(含加急费{money2}元)。请尽快确认订单任务。"),
        SHOP_AUTH_REJECTED("SMS_505925106", "门店端-资料审核被拒绝", "很遗憾,您的门店\"{storeName}\"未通过审核,原因:{reason},您可修改资料后重新提交。"),
        SHOP_AUTH_APPROVED_DEPOSIT("SMS_505705111", "门店端-审核通过需缴纳押金", "恭喜您!您的门店\"{storeName}\"已通过初步审核。请支付押金{money}元以完成入驻,支付后即可登录门店后台正式接单。"),
        SHOP_AUTH_SUCCESS("SMS_505810110", "门店端-成功入驻通知", "恭喜您!您的门店\"{storeName}\"已通过平台审核,正式入驻成功。您可登录商家后台开始接单,账号:{phone},初始密码:{password}(建议首次登录后修改)。"),
        ;
        private final String templateCode;
        private final String title;
        private final String content;
        public String format(String... params) {
            String result = this.content;
            for (int i = 0; i < params.length - 1; i += 2) {
                result = result.replace("{" + params[i] + "}", params[i + 1]);
            }
            return result;
        }
    }
    /**
     * 得到request对象
     *
     * @return
     */
    public static HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }
    public static String getIpAddr() {
        HttpServletRequest request = Constants.getRequest();
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
@@ -424,4 +682,46 @@
    }
    /**
     * 根据身份证号码获取性别
     * @param idCard 身份证号码(15位或18位)
     * @return 1-男,2-女,null-无法判断
     */
    public static Integer getGenderByIdCard(String idCard) {
        if (idCard == null || (idCard.length() != 15 && idCard.length() != 18)) {
            return null;
        }
        // 15位身份证:最后一位为性别码;18位身份证:第17位(索引16)为性别码
        int genderIndex = idCard.length() == 15 ? 14 : 16;
        int genderCode = Character.getNumericValue(idCard.charAt(genderIndex));
        return genderCode % 2 == 1 ? 1 : 2;
    }
    public static BigDecimal formatBigdecimal4Float(BigDecimal d) {
        if (d == null) {
            d = new BigDecimal(0.0);
        }
        //保留两位小数且四舍五入
        d = d.setScale(4, BigDecimal.ROUND_HALF_UP);
        return  d;
    }
    /**
     * 司机定级:5=S 4=A 3=B 2=C 1=D
     *
     * @param level 等级 1-5
     * @return 等级文本
     */
    public static String getDriverLevelName(Integer level) {
        if (level == null) return null;
        switch (level) {
            case 5: return "S";
            case 4: return "A";
            case 3: return "B";
            case 2: return "C";
            case 1: return "D";
            default: return null;
        }
    }
}