根据括号起始位置找到括号结束位置;附实例解析if else中的逻辑运算&&算数运算

其实就是利用Stack的后进先出特性实现找到对应括号的位置

如:根据自定义规则解析(其中的运算变量、条件变量 可以是前端数据的属性)

/**
 *  @author zhangxuewei
 *
 * 关键字:next; 、if、else if
 * 语法:
 * 支持嵌套描述,多组公式使用 next; 隔开,描述中所有符号均为英文符号,并且是压缩过后的描述不得存在换行符等其他无关文本
 *
 * 运算算公式1;
 * if(条件1){
 *   运算算公式2;
 * }else if(条件3){
 *   运算算公式3;
 * }
 * 运算算公式4;
 * next;
 * if(条件4){
 *   运算算公式5;
 * }else if(条件5){
 *   运算算公式6;
 *   if(条件6){
 *      运算算公式7;
 *   }
 *   运算算公式8;
 * }
 *
 *
 */

//如此公式配置:'num'*'goodsPrice'=gvalue5 if(og1=='否'||gvalue5 >10){'num'*'num'*'goodsPrice'=gvalue5}next;'num'*'gvalue5'=gvalue5
'num'*'goodsPrice'=gvalue5;

if(og1=='否'||gvalue5 >10){
    'num'*'num'*'goodsPrice'=gvalue5
}

next;

'num'*'gvalue5'=gvalue5;

后端java解析后返回的json格式:

[
    {
        "outsideStartFormulaList": [
            "gvalue5 |'num'*'goodsPrice'|num|goodsPrice"
        ], 
        "ifWhere": "og1=='否'||gvalue5 >10", 
        "ifWhereParam": "og1;否;gvalue5;10", 
        "insideStartFormulaList": [
            "gvalue5|'num'*'num'*'goodsPrice'|num|num|goodsPrice"
        ], 
        "sublevelFormulaDTOList": null, 
        "insideEndFormulaList": null, 
        "outsideEndFormulaList": null, 
        "allIfFormula": "'num'*'num'*'goodsPrice'=gvalue5"
    }, 
    {
        "outsideStartFormulaList": [
            "gvalue5|'num'*'gvalue5'|num|gvalue5"
        ], 
        "ifWhere": null, 
        "ifWhereParam": null, 
        "insideStartFormulaList": null, 
        "sublevelFormulaDTOList": null, 
        "insideEndFormulaList": null, 
        "outsideEndFormulaList": null, 
        "allIfFormula": null
    }
]

根据返回的json前端再进行递归解析使用eval函数进行运算

java代码:

import lombok.Data;

import java.util.List;

@Data
public class FormulaDTO {

    private List<String> outsideStartFormulaList;// 当前if 外的开始公式内容 (以英文分隔符 “;”隔离各个公式  )

    private String ifWhere;// 当前if 中的条件公式

    private String ifWhereParam;//当前if 中的条件公式中的参数

    private List<String> insideStartFormulaList;// 当前if 中的开始公式内容(以英文分隔符 “;”隔离各个公式  )

    private List<FormulaDTO> sublevelFormulaDTOList;// 当前if{}  中嵌套的if{}

    private List<String> insideEndFormulaList;// 当前if 中的结束公式内容(以英文分隔符 “;”隔离各个公式  )

    private List<String> outsideEndFormulaList;// 当前if 外的结束公式内容(以英文分隔符 “;”隔离各个公式 ,可以暂时不用,因为可以使用insideEndFormulaList代替,只不过会出现冗余描述)

    private String allIfFormula;//当前if{} 主体中的所有描述(递归参数)

}


import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zhangxuewei
 */
public class FormatFormulaUtils {

    public static final String VALUE_REGEX = "(?<==).*";//匹配value(匹配“=”之后的内容)

    public static final String COMPUTATIONAL_PROCESS_REGEX = ".+(?==)";//匹配计算过程(匹配“=”之前的内容)

    public static final String COMPUTATIONAL_PROCESS_PARAMS_REGEX = "\\w+";//匹配计算过程中的参数

    public static final String IF_WHERE = "[^='|<>!&\"]+";//匹配if条件中的参数

    /**
     * 获取格式化后的公式list
     *
     * @param formulasArray
     * @return
     */
    public static List<String> getFormatFormulaList(String[] formulasArray) {
        List<String> outsideStartFormulaList = new ArrayList<>();
        //转换公式:
        for (String outsideStartFormulasStr : formulasArray) {
            if (StringUtils.isEmpty(outsideStartFormulasStr.trim())) {
                continue;
            }
            String outsideStartFormatFormulas = FormatFormulaUtils.getFormatFormula(outsideStartFormulasStr);
            outsideStartFormulaList.add(outsideStartFormatFormulas);
        }
        return outsideStartFormulaList;
    }

    /**
     * 获取格式化后的公式
     * gvalue5|'num'*'goodsPrice'|num|goodsPrice
     *
     * @param formula
     * @return
     */
    public static String getFormatFormula(String formula) {
        if (StringUtils.isEmpty(formula.trim())) {
            return null;
        }
        //先获取value
        String value = getValue(formula);
        //获取计算过程
        String computationalProcess = getComputationalProcess(formula);
        //获取计算过程参数
        String computationalProcessParams = getComputationalProcessParams(formula);
        String formatFormula = value + "|" + computationalProcess + "|" + computationalProcessParams;
        return formatFormula;
    }


    /**
     * 获取计算过程中的参数
     * 如:gvalue5|'num'*'goodsPrice'|num|goodsPrice 中的 num|goodsPrice
     *
     * @param formula
     * @return
     */
    public static String getComputationalProcessParams(String formula) {
        String formulaProcess = getComputationalProcess(formula);
        Pattern p = Pattern.compile(COMPUTATIONAL_PROCESS_PARAMS_REGEX);
        Matcher m = p.matcher(formulaProcess);
        String formulaProcessParams = "";
        while (m.find())
            formulaProcessParams += m.group() + "|";
        if (formulaProcessParams.length() > 0)
            return formulaProcessParams.substring(0, formulaProcessParams.length() - 1);
        else
            return null;
    }

    /**
     * 获取计算过程
     *
     * @param formula
     * @return
     */
    public static String getComputationalProcess(String formula) {
        Pattern p = Pattern.compile(COMPUTATIONAL_PROCESS_REGEX);
        Matcher m = p.matcher(formula);
        m.find();
        return m.group();
    }

    /**
     * 获取等于号后的值
     *
     * @param formula
     * @return
     */
    public static String getValue(String formula) {
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(VALUE_REGEX);
        // 现在创建 matcher 对象
        Matcher m = r.matcher(formula);
        if (m.find())
            return m.group(0);
        else
            return null;
    }

    /**
     * @param ifWhereArray
     * @return
     */
    @Deprecated
    public static List<String> getIfWhereFormulaList(String[] ifWhereArray) {
        List<String> formatIfWhereList = new ArrayList<>();
        for (String ifWhere : ifWhereArray) {
            if (StringUtils.isEmpty(ifWhere.trim())) {
                continue;
            }
            String formatIfWhere = getIfWhereFormula(ifWhere);
            formatIfWhereList.add(formatIfWhere);
        }
        return formatIfWhereList;
    }


    /**
     * 获取计算过程中的参数
     * 如:gvalue5|'num'*'goodsPrice'|num|goodsPrice 中的 num|goodsPrice
     *
     * @param ifWhere
     * @return
     */
    @Deprecated
    public static String getIfWhereFormula(String ifWhere) {
        Pattern p = Pattern.compile(IF_WHERE);
        Matcher m = p.matcher(ifWhere);
        String formulaProcessParams = "";
        while (m.find())
            formulaProcessParams += m.group().trim() + ";";
        if (formulaProcessParams.length() > 0)
            return formulaProcessParams.substring(0, formulaProcessParams.length() - 1);
//            return ifWhere+""+formulaProcessParams.substring(0, formulaProcessParams.length() - 1);
        else
            return null;
    }


}
import nbpt.ts.zhaf.domain.dto.FormulaDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zhangxuewei
 */
public class FormulaUtils {

    public static void main(String[] args) {
        String formula = "'num'*'goodsPrice'=gvalue5 if(og1=='否'||gvalue5 >10){'num'*'num'*'goodsPrice'=gvalue5}next;'num'*'gvalue5'=gvalue5";
        List<FormulaDTO> formulaDTOList =  getFormulaList(formula);
        System.out.println(formulaDTOList.size());
    }

    /**
     * 获取多个格式化公式
     *
     * @param formula
     * @return
     */
    public static List<FormulaDTO> getFormulaList(String formula) {
        if (ObjectUtils.isEmpty(formula) || ObjectUtils.isEmpty(formula.trim()))
            return null;
        String[] formulaArray = formula.split("next;");
        List<FormulaDTO> formulaDTOList = new ArrayList<>();
        for (String formulaStr : formulaArray) {
            if (StringUtils.isEmpty(formulaStr.trim()))
                continue;
            FormulaDTO formulaDTO = getFormula(formulaStr);
            if (!ObjectUtils.isEmpty(formulaDTO))
                formulaDTOList.add(formulaDTO);
        }
        return formulaDTOList;
    }

    /**
     * 获取单个公式格式
     *
     * @param formula
     * @return
     */
    public static FormulaDTO getFormula(String formula) {
        FormulaDTO formulaVO = new FormulaDTO();
        formulaVO.setAllIfFormula(formula);
        FormulaDTO f = convertFormula(formula, formulaVO);
        if (!ObjectUtils.isEmpty(f.getSublevelFormulaDTOList()) && f.getSublevelFormulaDTOList().size() > 0) {
            return f.getSublevelFormulaDTOList().get(0);
        }
        return null;
    }

    public static FormulaDTO convertFormula(String formula, FormulaDTO formulaVO) {
        String formulas[] = formula.split("else");
        if (formulas.length == 0) {
            return null;
        }
        List<FormulaDTO> formulaDTOList = new ArrayList<>();
        for (String f : formulas) {
            Boolean existNestIf = false;
            FormulaDTO formulaDTO = new FormulaDTO();
            //当前if 外的开始公式内容
            Integer outsideStartFormulasStrIndex = f.indexOf("if");
            if (outsideStartFormulasStrIndex < 0) {
                //普通计算公式
                String[] formulaArr = f.split(";");
                List<String> formatFormulaList = FormatFormulaUtils.getFormatFormulaList(formulaArr);
                formulaDTO.setOutsideStartFormulaList(formatFormulaList);
                FormulaDTO subFormula = new FormulaDTO();
                BeanUtils.copyProperties(formulaDTO, subFormula);
                formulaDTOList.add(subFormula);
                formulaDTO.setSublevelFormulaDTOList(formulaDTOList);
                return formulaDTO;
            }
            if (outsideStartFormulasStrIndex > 0) {
                String[] outsideStartFormulasArrayStr = f.substring(0, outsideStartFormulasStrIndex).split(";");
                if (outsideStartFormulasArrayStr.length > 0) {
                    List<String> outsideStartFormulaList = FormatFormulaUtils.getFormatFormulaList(outsideStartFormulasArrayStr);
                    if (outsideStartFormulaList.size() > 0)
                        formulaDTO.setOutsideStartFormulaList(outsideStartFormulaList);
                }
            }
            //当前if 中的条件公式
            Integer ifWhereListStartIndex = f.indexOf("(");
            Integer ifWhereListEndIndex = bracketsMatchedSearchByLeft(f.toCharArray(), ifWhereListStartIndex);
            String ifWhereStr = f.substring(ifWhereListStartIndex + 1, ifWhereListEndIndex);
            String formatIfWhereStr = FormatFormulaUtils.getIfWhereFormula(ifWhereStr);
            formulaDTO.setIfWhere(ifWhereStr);
            formulaDTO.setIfWhereParam(formatIfWhereStr);


            //当前if{} 主体中的所有描述---
            Integer allIfFormulaStartIndex = f.indexOf("{");
            Integer allIfFormulaEndIndex = bracketsMatchedSearchByLeft(f.toCharArray(), allIfFormulaStartIndex);
            String allIfFormula = f.substring(allIfFormulaStartIndex + 1, allIfFormulaEndIndex);
            formulaDTO.setAllIfFormula(allIfFormula);

            //当前if 内的开始公式内容
            Integer insideStartFormulaEndIndex = allIfFormula.indexOf("if");
            String insideStartFormulaStr;
            if (insideStartFormulaEndIndex < 0) {//说明当前if中不存在 嵌套if
                Integer insideStartFormulaStartIndex = f.indexOf("{");
                insideStartFormulaEndIndex = f.indexOf("}");
                //截取公式
                insideStartFormulaStr = f.substring(insideStartFormulaStartIndex + 1, insideStartFormulaEndIndex);
            } else {
                insideStartFormulaStr = allIfFormula.substring(0, insideStartFormulaEndIndex);
                existNestIf = true;
            }
            String insideStartFormulaArrStr[] = insideStartFormulaStr.split(";");
            if (insideStartFormulaArrStr.length > 0) {
                List<String> insideStartFormulaList = FormatFormulaUtils.getFormatFormulaList(insideStartFormulaArrStr);
                if (insideStartFormulaList.size() > 0)
                    formulaDTO.setInsideStartFormulaList(insideStartFormulaList);//前if 中的开始公式内容
            }

            Integer insideEndFormulaStartIndex = -1;
            //当前if 内的结束公式内容
            if (existNestIf) {//存在嵌套的if
                insideEndFormulaStartIndex = allIfFormula.lastIndexOf("}");
                String insideEndFormulaStr = allIfFormula.substring(insideEndFormulaStartIndex + 1, allIfFormula.length());
                String[] insideEndFormulaArrayStr = insideEndFormulaStr.split(";");
                List<String> insideEndFormulaList = FormatFormulaUtils.getFormatFormulaList(insideEndFormulaArrayStr);
                if (insideEndFormulaList.size() > 0)
                    formulaDTO.setInsideEndFormulaList(insideEndFormulaList);
            }

            if (existNestIf) {//存在嵌套if
                //获取嵌套if内容
                String subFormula = allIfFormula.substring(insideStartFormulaEndIndex, insideEndFormulaStartIndex + 1);
                convertFormula(subFormula, formulaDTO);
                //判断是否存在 outsideEndFormulaList 当前if 外的结束公式内容
                if (allIfFormula.indexOf("}") > 0) {
                    String outsideEndFormulaArrayStr = f.substring(allIfFormulaEndIndex, f.length());
                    String[] outsideEndFormulaArray = outsideEndFormulaArrayStr.split(";");
                    List<String> outsideEndFormulaList = FormatFormulaUtils.getFormatFormulaList(outsideEndFormulaArray);
                    formulaDTO.setOutsideEndFormulaList(outsideEndFormulaList);
                }
            }
            formulaDTOList.add(formulaDTO);
        }
        formulaVO.setSublevelFormulaDTOList(formulaDTOList);
        return formulaVO;
    }

    /**
     * 通过左括号的位置得到匹配的右括号的位置
     * <p>
     * 返回对应坐标为正常,
     * -1表示传进来的坐标不是左括号
     * -2表示不存在对应右括号(不应该出现,应该提前校验过括号配对)
     *
     * @param checkedCharArray
     * @param leftIndex
     * @return
     */
    public static Integer bracketsMatchedSearchByLeft(char[] checkedCharArray, int leftIndex) {

        // 校验传进来的数组和索引是否为合法
        if (checkedCharArray.length < leftIndex || leftIndex < 0) {
            return -1;
        }

        char left = checkedCharArray[leftIndex];
        // 非左括号或空格
        if (!('(' == left || '{' == left)) {
            return -1;
        }

        /*
         *  获取传进来的是第几个左括号
         */
        int startIndex = 0;
        Matcher matcher = Pattern.compile("\\(|\\{").matcher(new String(checkedCharArray));
        while (matcher.find()) {
            startIndex++;
            if (matcher.start() == leftIndex) {
                break;
            }
        }
        /*
         *  获取另一配对括号位置
         */
        Stack<Character> bracketsStack = new Stack<Character>();
        int appearCount = 0;
        for (int i = 0; i < checkedCharArray.length; i++) {
            char c = checkedCharArray[i];
            // 左括号都压入栈顶,右括号进行比对
            if (c == '(' || c == '{') {
                appearCount++;
                // 如果是目标,就插入*作为标记
                if (startIndex == appearCount) {
                    bracketsStack.push('*');
                } else {
                    bracketsStack.push(c);
                }
//                System.out.println("栈内容:" + bracketsStack);
            } else if (c == ')' || c == '}') {
                // 栈非空校验,防止首先出现的是右括号
                if (bracketsStack.isEmpty()) {
                    return -2;
                }
                Character popChar = bracketsStack.pop();
                if ('*' == popChar) {
                    return i;
                }
            }
        }
        return -2;
    }

    /**
     * 校验字符串中的括号是否匹配
     *
     * @param s
     * @return
     */
    public static boolean isMatch(String s) {
        //定义左右括号的对应关系
        Map<Character, Character> bracket = new HashMap<Character, Character>();
        bracket.put(')', '(');
        bracket.put('}', '{');

        Stack<Character> stack = new Stack<Character>();

        for (int i = 0; i < s.length(); i++) {
            Character temp = s.charAt(i);//先转换成字符
            //是否为左括号
            if (bracket.containsValue(temp)) {
                stack.push(temp);
                //是否为右括号
            } else if (bracket.containsKey(temp)) {
                if (stack.isEmpty()) {
                    return false;
                }
                //若左右括号匹配
                if (stack.peek() == bracket.get(temp)) {
                    stack.pop();
                } else {
                    return false;
                }
            }
        }
        return stack.isEmpty() ? true : false;
    }
}

    //公式解析器
    function formulaResolver(gsConf) {
        var gsList = new Array();
        var gsArr = gsConf.split(";");
        if (gsConf.length > 0) {
            for (i = 0; i < gsArr.length; i++) {
                var arr2 = gsArr[i].split("|");
                var _params = new Array();
                for (j = 2; j < arr2.length; j++) {
                    _params.push(arr2[j].trim());
                }
                gsList.push({
                    rst: arr2[0].trim(),//结果参数
                    gs: arr2[1].trim(),//公式
                    params: _params//公式中的参数
                });
            }
        }
        return gsList;
    }

    //if条件公式解析
    function ifWhereResolver(gsConf, paramStr) {
        var gsList = new Array();
        var _params = paramStr.split(";");
        if (gsConf.length > 0) {
            gsList.push({
                gs: gsConf.trim(),//公式
                params: _params//公式中的参数
            });
        }
        return gsList;
    }

    /**
     * if描述性公式结果计算
     * @param data excle中的值
     * @param obj excle单行对象
     * @param i data下标
     * @param ifFormulaList 公式
     * @param isNestMethod 是否为嵌套方法进入
     */
    function orderGoodsIfSum(data, obj, i, ifFormulaList, isNestMethod) {//zxwcao
        for (var ifIndex = 0; ifIndex < ifFormulaList.length; ifIndex++) {
            var ifFormula = ifFormulaList[ifIndex];
            //1、先获取outsideStartFormulaList进行执行
            if (ifFormula.outsideStartFormulaList) {
                var outsideStartFormulaList = ifFormula.outsideStartFormulaList;//当前if 外的开始公式内容
                for (var outsideStartFormulaIndex = 0; outsideStartFormulaIndex < outsideStartFormulaList.length; outsideStartFormulaList++) {
                    //执行公式解析
                    var gsList = formulaResolver(outsideStartFormulaList[outsideStartFormulaIndex]);
                    // 并计算
                    orderGoodsSum(gsList, data, obj, i);
                }
            }
            //2、判断ifWhereList是否为空
            if (ifFormula.ifWhere) {
                var ifWhere = ifFormula.ifWhere;
                var ifWhereParam = ifFormula.ifWhereParam;
                var ifWhereGsList = ifWhereResolver(ifWhere, ifWhereParam);
                var ifWhereResult = ifWhereSum(ifWhereGsList, data, obj, i)
                if (ifWhereResult) {//if条件走通
                    //判断 insideStartFormulaList 存不存在
                    if (ifFormula.insideStartFormulaList) {
                        //3、获取格式化计算公式
                        for (var insideStartFormulaIndex = 0; insideStartFormulaIndex < ifFormula.insideStartFormulaList.length; insideStartFormulaIndex++) {
                            var insideStartFormula = ifFormula.insideStartFormulaList[insideStartFormulaIndex]
                            var gsList = formulaResolver(insideStartFormula);
                            orderGoodsSum(gsList, data, obj, i);
                        }
                        //4、判断是否存在子集
                        if (ifFormula.sublevelFormulaDTOList) {
                            var isNestMethod = true;
                            //递归调用当前方法
                            orderGoodsIfSum(data, obj, i, ifFormula.sublevelFormulaDTOList, isNestMethod);
                            //5、判断是否存在insideEndFormulaList
                            if (ifFormula.insideEndFormulaList) {
                                //执行 insideEndFormulaList
                                for (var insideEndFormulaIndex = 0; insideEndFormulaIndex < ifFormula.insideEndFormulaList.length; insideEndFormulaIndex++) {
                                    var insideEndFormula = ifFormula.outsideEndFormulaList[insideEndFormulaIndex]
                                    var gsList = formulaResolver(insideEndFormula);
                                    orderGoodsSum(gsList, data, obj, i);
                                }
                            }
                        }
                        //判断是否为:嵌套进入
                        if (isNestMethod) {
                            //判断是否存在:outsideEndFormulaList
                            if (ifFormula.outsideEndFormulaList) {
                                for (var outsideEndFormulaIndex = 0; outsideEndFormulaIndex < ifFormula.outsideEndFormulaList.length; outsideEndFormulaIndex++) {
                                    var outsideEndFormula = ifFormula.outsideEndFormulaList[outsideEndFormulaIndex]
                                    var gsList = formulaResolver(outsideEndFormula);
                                    orderGoodsSum(gsList, data, obj, i);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    //条件公式结果计算
    function ifWhereSum(ifWhereGsList, data, obj, i) {
        for (n = 0; n < ifWhereGsList.length; n++) {
            var tmpGS = ifWhereGsList[n].gs;
            for (m = 0; m < ifWhereGsList[n].params.length; m++) {
                //判断参数是否为数值类型 ifWhereGsList[n].params[m]
                if (!Number.isFinite(ifWhereGsList[n].params[m] * 1)) {
                    if (obj[ifWhereGsList[n].params[m]]) {
                        tmpGS = tmpGS.replace(ifWhereGsList[n].params[m], '\'' + obj[ifWhereGsList[n].params[m]] + '\'');
                    }
                }
            }
            if (tmpGS) {
                return eval(tmpGS);
            } else {
                return -1;
            }
        }
    }

    /**
     * 普通公式结果计算
     * @param gsList 公式
     * @param data excle中的list对象
     * @param obj 用于存放data中的对象
     * @param i data的下标
     * @returns {boolean}
     */
    function orderGoodsSum(gsList, data, obj, i) {
        for (n = 0; n < gsList.length; n++) {
            var tmpGS = gsList[n].gs;
            if (gsList[n].params.length == 1 && gsList[n].params[0] == "eval") {
                var t = data[i][gsList[n].rst];//obj[ gsList[n].rst ];//$(rows[i]).find('input[name="'+gsList[n].rst+'"]').val();
                eval(tmpGS.replace(gsList[n].rst, t));//"t = math.max(gvalue5,0.3)"
                obj[gsList[n].rst] = t;
                data[i][gsList[n].rst] = obj[gsList[n].rst];
                needReload = true;
            } else {
                for (m = 0; m < gsList[n].params.length; m++) {
                    if (/^-?[0-9]+.?[0-9]*/.test(obj[gsList[n].params[m]]) == false) {
                        layer.msg("第" + (i + 1) + "行,自动计算公式的参数需要填数值!", {time: 1500}, function () {
                        });
                        return false;
                    }
                    tmpGS = tmpGS.replace("'" + gsList[n].params[m] + "'", obj[gsList[n].params[m]]);
                }
                if (tmpGS) {
                    obj[gsList[n].rst] = math.parser().eval(tmpGS).toString();
                }
                data[i][gsList[n].rst] = obj[gsList[n].rst];
                needReload = true;
            }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值