制定直线方程式和多项式方程式并显示:Django + js + highcharts

一、本文目的:

最近为一家企业做一个网站系统,涉及到一些指标公式的制定和显示问题。其中指标公式的制定包括:直线方程式、多项式方程式以及由这两种方程式组合的分段函数。经过讨论,方案如下:

1、使用适合的数据结构进行相关字段的存储和解析:x的区间、直线的斜率和偏置、多项式的系数等。

2、后台使用python进行相关字段的解析和处理。

3、前端使用js进行相关字段的解析,并使用highcharts进行显示。

本文的贡献如下:

1、实现了直线方程式、多项式方程式以及由这两种方程式组合的分段函数,使得用户可以根据需求,制定相关的公式。

2、通过js和bootstrap实现了较好的用户交互界面,用户可添加任意数量的直线方程式或者多项式方程式,同时还可以删除由于误操作添加的方程式。

3、实现了分段函数的显示:直线方程式 + 曲线方程式。

效果如下:

二、准备工作:

1、搭建【django】开发环境:http://blog.csdn.net/houchaoqun_xmu/article/details/53693347 

2、下载【highcharts】插件:https://www.hcharts.cn/demo/highcharts

3、下载【jQuery】插件:http://jquery.com/download/

三、本文核心:

1、添加多项式方式的输入框,并提供删除功能,如下图所示:

2、数据结构:

一般情况:没有分段函数

=== x_Value:存储直线和多项式方程中x的区间,以下划线“_”分隔,形如:0_100表示从0到100。

=== k_Value:存储直线方程的斜率,多项式方程中带有未知数x的系数(以分号;分隔)。

=== b_Value:存储直线方程的偏置,多项式方程中不带未知数x的系数。

特殊情况:含有分段函数,直线+直线、直线+多项式、多项式+多项式

如下图所示为“直线+多项式+直线”的模式,以此为例,分析 x_Value、k_Value 和 b_Value 的取值:

=== x_Value = 0_7_28_inf,表示区间[0, 7]、[7, 28]和[28, 正无穷]

=== k_Value = 0_ 0.00346;-0.15469;-2.93331_0,以下划线_为分隔符分别表示3个曲线对应的值,第一个0对应区间[0, 7]中直线方程的斜率、0.00346;-0.15469;-2.93331对应区间[7, 28]中多项式方程未知数的系数,第二个0对应区间[28, 正无穷]中直线方程的斜率。值得一提的是,如何判别是普通直线或者多项式方程的办法就是通过分号【;】进行判断。

=== b_Value = 100_127.46927_0,对应3个区间的3个偏置项。

3、解析【x_Value】【k_Value】【b_Value】,并分别对直线方程和多项式方程进行处理:

通过函数 strip() 和 split() 将字符串通过下划线_分隔为list[ ]

X_list = x_Value.strip().split('_')
K_list = k_Value.strip().split('_')
B_list = b_Value.strip().split('_')

根据上述的例子,处理后如下所示:

=== X_list = [u'0', u'7', u'28', u'inf']

=== K_list = [u'0', u' 0.00346;-0.15469;-2.93331', u'0']

=== B_list = [u'100', u'127.46927', u'0']
根据 K_list[ ] 进行分段处理,K_list[i]中不存在分号【;】的就是普通直线,存在分号【;】的就是多项式方程,如下所示:

for k in K_list:
    # print k
    expression = ""
    if k.find(";") == -1:
        print "=== line ==="
        if K_list[i]=='0':
            expression = "y = " + B_list[i]
        elif K_list[i]=='1':
            if (B_list[i]).find("-") == -1:
                if B_list[i]==0:
                    expression = "y = x"
                else:
                    expression = "y = x + " + B_list[i]
            else:
                expression = "y = x " + B_list[i]
        else:
            if (B_list[i]).find("-") == -1:
                if B_list[i]==0:
                    expression = "y = " + K_list[i] + "x"
                else:
                    expression = "y = " + K_list[i] + "x + " + B_list[i]
            else:
                expression = "y = " + K_list[i] + "x " + B_list[i]
    else:
        print "=== curve ==="
        curve_list = k.strip().split(';')
        j = 0
        curve_len = len(curve_list)
        print "curve_len = ",curve_len
        for j in range(curve_len):
            # exponent: 指数
            # curve_list[j]: 系数
            exponent = str(curve_len - j)
            print "exponent = ",exponent
            if curve_list[j] == "0":
                expression = expression
            elif curve_list[j] == "1":
                if exponent == "1":
                    expression = expression + " + x"
                else:
                    expression = expression + " + " + "x^" + exponent
            elif curve_list[j] == "-1":
                if exponent == "1":
                    expression = expression + " - x "
                else:
                    expression = expression + " - x^" + exponent
            # coefficient > 0 except 1
            elif (curve_list[j]).find("-") == -1:
                if exponent == "1":
                    # the begin position.
                    if j == 0:
                        expression = curve_list[j] + "x"
                    else:
                        expression = expression + " + " + curve_list[j] + "x"
                else:
                    if j == 0:
                        expression = curve_list[j] + "x^" + exponent
                    else:
                        expression = expression + " + " + curve_list[j] + "x^" + exponent
            # coefficient < 0 except -1
            else:
                if exponent == "1":
                    expression = expression + curve_list[j] + "x"
                else:
                    expression = expression + curve_list[j] + "x^" + exponent
                    
        if (B_list[i]).find("-") == -1:
            expression = "y = " + expression + " + " + B_list[i]
        else:
            expression = "y = " + expression + B_list[i]
    expressions_list.append(display_expression(X_list[i], X_list[i+1], expression))

    i = i + 1

使用类 display_expression 存储每一个区间的信息,包括区间的起始位置和表达式,如下所示:

### class ### 
class display_expression:
	def __init__(self, x_start, x_end, expression):
		self.x_start = x_start
		self.x_end = x_end
		self.expression = expression

注:js的解析和处理思想类似。

 

四、实现步骤:

1、基于django,创建一个工程SettingFormula和app_SettingFormula:

python .\django-admin.py startproject SettingFormula
python .\manage.py startapp app_SettingFormula

2、配置settings.py:

=== 在【INSTALLED_APPS】处加入新建的app_SettingFormula

=== 配置static和templates:

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'templates'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

3、引入相关的.js和.css文件

<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/Water.css' %}">

<script type="text/javascript" src = "{% static 'js/jquery.min.js' %}" ></script>
<script type="text/javascript" src = "{% static 'js/bootstrap.js' %}" ></script>
<script type="text/javascript" src = "{% static 'js/highcharts.js' %}" ></script>

4、实现简单的html界面

<div style="text-align: center;">
    <label style="font-size: 18px;">公式的定制:直线方程式 + 多项式方程式</label>
</div>

<div class="row" style="padding-top: 30px;">
    <div class="col-md-3"></div>
    <!-- 定制指标公式 - 相关信息 -->
    <div class="col-md-6">
        <div class="panel" style="border: 1px solid #e0e0e0;">
            <div class="panel-heading">
                <label>制定直线方程式和多项式方程式:</label>
                <button id="btn_save" class="btn btn-sm btn-success pull-right" type="button">保存设置</button>
            </div>
            <div style="text-align: center;padding: 5px 0;background-color: #f0f0f0;">
                <input id="newBtn" class="btn btn-sm btn-success" type="button" value="添加直线方程">
                <a class="btn btn-sm btn-success" data-toggle="modal" data-target="#Add_curve" role="button">添加多项式方程</a>
            </div>
            <div class="panel-body">
                <table id="IndicatorFormula_modify">
                    <tr></tr>
                </table> 
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-3"></div>
    <div class="col-md-6">
        <div class="panel" style="border: 1px solid #e0e0e0;">
            <div class="panel-heading">
                <label>当前指标公式信息:</label>
            </div>
            <div class="panel-body">
                <table class="" style="margin: 5px;">
                    {% for expression in expressions_list %}
                        <tr style="font-size: 15px;">
                            <td><span class="glyphicon glyphicon-hand-right"></span> 区间:[{{ expression.x_start }} , {{ expression.x_end }}]</td>
                            <td width="5%"></td>
                            <td>表达式:{{expression.expression}}</td>
                        </tr>
                    {% endfor %}
                </table>
            </div>
        </div>
    </div>
</div>

<div class="row">
    <div class="col-md-3"></div>
    <div class="col-md-6">
        <div id="LineContainer_test"></div>
    </div>
</div>
<br>

<div class="modal fade" id="Add_curve">
    <div class="modal-dialog" style="width:300px;">
        <div class="modal-content">
            <div class="modal-body">
                请输入曲线最高次指数:<input type="text" id="curve_num" style="width:60px;">
                <input id="newBtn_curve" class="btn-sm btn-success pull-right" type="button" value="确定">
            </div>
        </div>
    </div>  
</div>

5、使用js实现用户点击“添加直线方程”和“添加多项式方程”弹出对应的输入框:

// line
$("#newBtn").bind("click", function(){
    // console.log(this.id)
    // console.log(count);
    var seq = count.toString();
    // console.log(seq);
    line_num.push(1);
    
    $str = ""
    $str += "<tr>";
    $str += "<td>";
    $str += "起始点: x_0 = <input id=\"x" + seq + "\" name=\"input_x\" type=\"text\" style=\"width: 40px;\">  ";
    $str += "截止点: x_1 = <input id=\"x" + seq + "\" name=\"input_x_1\" type=\"text\" style=\"width: 40px;\">  ";
    $str += "<td>";
    $str += "直线斜率 = <input id=\"k" + seq + "\" name=\"input_k\" type=\"text\" style=\"width: 40px;\">";
    $str += "</td>";
    $str += "<td>";
    $str += "直线偏置 = <input id=\"y" + seq + "\" name=\"input_b\" type=\"text\" style=\"width: 40px;\">";
    $str += "</td>";
    $str += "<td width=\"10%\"><input id=\"deleteLine_" + count + "\" class = \"btn btn-sm btn-success\" type=\"button\" value=\"删除表达式\" onClick='getDel(this)'></td>";
    $str += "</tr>";

    $("#IndicatorFormula_modify").append($str);

    count++;
}); 

// curve
$("#newBtn_curve").bind("click", function(){
    var curve_num = $("#curve_num").val();
    // console.log(curve_num);
    if(curve_num > 0){
        $('#Add_curve').modal('hide');

        line_num.push(parseInt(curve_num));
        var count_curve = 0;

        var seq = count.toString();

        var curve_length = curve_num;
        var seq_curve = count_curve.toString();

        $str = ""
        $str += "<tr style='color:#960000;' id='curveID_0'>";
        $str += "<td>";
        $str += "起始点: x_0 = <input id=\"x" + seq + "\" name=\"input_x\" type=\"text\" style=\"width: 40px;\">  ";
        $str += "截止点: x_1 = <input id=\"x" + seq + "\" name=\"input_x_1\" type=\"text\" style=\"width: 40px;\">  ";
        $str += "<td>";
        $str += "曲线系数 = <input id= coefficient_" + curve_length.toString() + " name=\"input_k\"" + " type=\"text\" style=\"width: 40px;\">  " + "x^" + curve_length;
        $str += "</td><td></td>";
        $str += "<td width=\"10%\"><input id=\"deleteLine_" + count_curve + "\" class = \"btn btn-sm btn-success\" type=\"button\" value=\"删除表达式\" onClick='getDelCurve(" + curve_num.toString() + ")'></td>";
        $str += "</tr>";

        $("#IndicatorFormula_modify").append($str);
        count_curve++;

        for(var i = count_curve; i <= curve_length; i++){
            var seq_curve = i.toString();
            var curveID = 'curveID_' + i.toString();
            var curve_tr_content = "style = 'color:#960000;' id = " + curveID;
            $str = ""
            $str += "<tr " + curve_tr_content + ">";
            $str += "<td></td>";
            $str += "<td>";
            if ((curve_length - i) != 0)
            {
                $str += "曲线系数 = <input id= coefficient_" + (curve_length - i).toString() + " name=\"input_k\"" + " type=\"text\" style=\"width: 40px;\">  " + "x^" + (curve_length - i);
            }
            else
            {
                $str += "曲线偏置 = <input id=\"y" + seq + "\" name=\"input_b\" type=\"text\" style=\"width: 40px;\">";
            }
            $str += "</td><td></td>";
            $str += "<td></td>";
            $str += "</tr>";

            $("#IndicatorFormula_modify").append($str);
        }
    }else{
        alert("请输入大于0的数值!");
    }

    count++;

});

6、删除直线方程和多项式方程的输入框:

// delete line input
function getDel(select_remove){
    $(select_remove).parent().parent().remove();
}

// delete curve input
function getDelCurve(delete_num){
     delete_num = parseInt(delete_num);
     for(var i = 0; i <= delete_num; i++){
         delete_id = "curveID_" + i.toString();
         console.log(delete_id);
         $("tr[id=" + delete_id + "]").remove();
      }
}

7、将用户填写的数据通过post方法提交至后台:

function post(URL, PARAMS) {        
    var temp = document.createElement("form");        
    temp.action = URL.toString();
    temp.method = "post";        
    temp.style.display = "none";        
    for (var x in PARAMS) {        
      var opt = document.createElement("textarea");        
      opt.name = x;        
      opt.value = PARAMS[x];
      console.log(opt.value);
      temp.appendChild(opt);
    }        
    // alert("xx");
    document.body.appendChild(temp);        
    temp.submit();        
    return temp;
}

function IsNum(s)
{
    if(s.toLowerCase() == "inf"){
        return true;
    }

    if (s!=null && s!="")
    {
        return !isNaN(s);
    }
    return false;
}

 

$("#btn_save").bind("click", function(){
    var x = "";
    var b = "";
    var k = "";
    var x_list = document.getElementsByName("input_x");
    var b_list = document.getElementsByName("input_b");     // y 表示偏置b
    var k_list = document.getElementsByName("input_k");
    var x_1_list = document.getElementsByName("input_x_1");

    // console.log(x_list);
    // console.log(b_list);
    // console.log(k_list);
    // console.log(x_1_list);

    for (var i = 0; i < x_list.length; ++i)
    {
        // alert("ss");
        if(!IsNum(x_list[i].value) || !IsNum(b_list[i].value) || !IsNum(x_1_list[i].value))
        {
            alert("请确认输入都为数字或者[Inf]表示无限大.");
            return;
        }

        if(parseFloat(x_list[i]) > 1 || parseFloat(x_list[i]) < 0)
        {
            alert(x_list[i].id + "输入不合法。");
            return;
        }
        if(parseFloat(b_list[i]) > 100 || parseFloat(x_list[i]) < 0)
        {
            alert(b_list[i].id + "输入不合法。");
            return;
        }
    }

    for (var i = 0; i < k_list.length; ++i)
    {
        if(!IsNum(k_list[i].value))
        {
            alert("请确认输入都为数字");
            return;
        }
    }

    var k_seq = 0;

    for (var i = 0; i < x_list.length; ++i)
    {
        x = x + x_list[i].value + "_";
        b = b + b_list[i].value + "_";
        var sub_k = "";
        for (var j = 0; j < line_num[i]; ++j)
        {
            sub_k = sub_k + k_list[k_seq + j].value + ";";
            // console.log("k_seq: " + k_seq + j);
        }
        k_seq = k_seq + line_num[i];
        sub_k = sub_k.substring(0, sub_k.length - 1);
        k = k + sub_k + "_";
    }

    x = x + x_1_list[x_1_list.length - 1].value

    // console.log(b_list[b_list.length - 1].value)
    // console.log(x_list[x_list.length - 1].value)
    // console.log()
    // console.log(b);
    b = b.substring(0, b.length - 1);
    k = k.substring(0, k.length - 1);
    // console.log(x);
    // console.log(b);
    // console.log(k);
    // console.log(typeof(k));
    post("", { x_Value: x, b_Value: b, k_Value: k });
}); 

8、根据post传来的数据,后台使用python进行数据处理:

def get_IndicatorFormula_expression(x_Value, k_Value, b_Value):
    X_list = x_Value.strip().split('_')
    K_list = k_Value.strip().split('_')
    B_list = b_Value.strip().split('_')

    # print "---"
    # print "X_list",X_list
    # print "B_list",B_list

    i = 0
    expressions_list = []

    # line and curve
    # find()函数找不到时返回为-1。
    for k in K_list:
        # print k
        expression = ""
        if k.find(";") == -1:
            print "=== line ==="
            if K_list[i]=='0':
                expression = "y = " + B_list[i]
            elif K_list[i]=='1':
                if (B_list[i]).find("-") == -1:
                    if B_list[i]==0:
                        expression = "y = x"
                    else:
                        expression = "y = x + " + B_list[i]
                else:
                    expression = "y = x " + B_list[i]
            else:
                if (B_list[i]).find("-") == -1:
                    if B_list[i]==0:
                        expression = "y = " + K_list[i] + "x"
                    else:
                        expression = "y = " + K_list[i] + "x + " + B_list[i]
                else:
                    expression = "y = " + K_list[i] + "x " + B_list[i]
        else:
            print "=== curve ==="
            curve_list = k.strip().split(';')
            j = 0
            curve_len = len(curve_list)
            print "curve_len = ",curve_len
            for j in range(curve_len):
                # exponent: 指数
                # curve_list[j]: 系数
                exponent = str(curve_len - j)
                print "exponent = ",exponent
                if curve_list[j] == "0":
                    expression = expression
                elif curve_list[j] == "1":
                    if exponent == "1":
                        expression = expression + " + x"
                    else:
                        expression = expression + " + " + "x^" + exponent
                elif curve_list[j] == "-1":
                    if exponent == "1":
                        expression = expression + " - x "
                    else:
                        expression = expression + " - x^" + exponent
                # coefficient > 0 except 1
                elif (curve_list[j]).find("-") == -1:
                    if exponent == "1":
                        # the begin position.
                        if j == 0:
                            expression = curve_list[j] + "x"
                        else:
                            expression = expression + " + " + curve_list[j] + "x"
                    else:
                        if j == 0:
                            expression = curve_list[j] + "x^" + exponent
                        else:
                            expression = expression + " + " + curve_list[j] + "x^" + exponent
                # coefficient < 0 except -1
                else:
                    if exponent == "1":
                        expression = expression + curve_list[j] + "x"
                    else:
                        expression = expression + curve_list[j] + "x^" + exponent
                        
            if (B_list[i]).find("-") == -1:
                expression = "y = " + expression + " + " + B_list[i]
            else:
                expression = "y = " + expression + B_list[i]
        expressions_list.append(display_expression(X_list[i], X_list[i+1], expression))

        i = i + 1

    return expressions_list

9、基于highcharts绘制坐标图:

$(function () {
    var x = "{{ x_Value }}", b = "{{ b_Value }}", k = "{{ k_Value }}";
    var i;
    var xValue = x.split("_");
    var bValue = b.split("_");
    var kValue = k.split("_");  // 未知量的系数
    // console.log(xValue);
    // console.log(bValue);
    // console.log(kValue);
    // console.log(parseFloat(xValue[2] * kValue[1]) + parseFloat(bValue[1]));
    // console.log();

    var data = new Array();
    // 判断线段的类型:
    // 1、只有直线
    // 2、有直线,又有曲线
    var has_curve = false;
    // 如果包含子串,则返回大于等于0的索引,否则返回-1
    
    for(var k = 0; k < kValue.length; k++){
        if(kValue[k].indexOf(";")>=0){
            has_curve = true;
            break;
        }
    }
    
    // has_curve == true 表示包含曲线
    if(has_curve == true){
        console.log("there is curve.");
        for(i = 0; i < bValue.length; i++){
            if((xValue[i+1]) && (xValue[i+1].toLowerCase() == "inf")){
                xValue[i+1] = 2 * xValue[i] + 40;
            }

            if(kValue[i].indexOf(";")>=0){
                // 曲线处理
                coefficient_list = kValue[i].split(";");
                var y_0 = 0, y_1 = 0, y_2 = 0, y_3 = 0, y_4 = 0, y_5 = 0;

                for(var k = 0; k < coefficient_list.length; k++){
                    y_0 = y_0 + parseFloat(coefficient_list[k]) * Math.pow(xValue[i], parseInt( coefficient_list.length - k));
                    y_1 = y_1 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/4), parseInt( coefficient_list.length - k));
                    y_2 = y_2 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/2), parseInt( coefficient_list.length - k));
                    y_3 = y_3 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/1.5), parseInt( coefficient_list.length - k));
                    y_4 = y_4 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/1.2), parseInt( coefficient_list.length - k));
                    y_5 = y_5 + parseFloat(coefficient_list[k]) * Math.pow(xValue[i+1], parseInt( coefficient_list.length - k));
                }
                y_0 = y_0 + parseFloat(bValue[i]);
                y_0 = y_0.toFixed(2);
                data.push([parseFloat(xValue[i]), parseFloat(y_0)]);

                y_1 = y_1 + parseFloat(bValue[i]);
                y_1 = y_1.toFixed(2);
                data.push([parseFloat(parseInt(xValue[i+1]/4)), parseFloat(y_1)]);

                y_2 = y_2 + parseFloat(bValue[i]);
                y_2 = y_2.toFixed(2);
                data.push([parseFloat(parseInt(xValue[i+1]/2)), parseFloat(y_2)]);

                y_3 = y_3 + parseFloat(bValue[i]);
                y_3 = y_3.toFixed(2);
                data.push([parseFloat(parseInt(xValue[i+1]/1.5)), parseFloat(y_3)]);

                y_4 = y_4 + parseFloat(bValue[i]);
                y_4 = y_4.toFixed(2);
                data.push([parseFloat(parseInt(xValue[i+1]/1.2)), parseFloat(y_4)]);

                y_5 = y_5 + parseFloat(bValue[i]);
                y_5 = y_5.toFixed(2);
                data.push([parseFloat(xValue[i+1]), parseFloat(y_5)]);
            }
            else{
                // 直线处理
                var y_0 = parseFloat((xValue[i]) * kValue[i]) + parseFloat(bValue[i]);
                y_0 = y_0.toFixed(2);
                data.push([parseFloat(xValue[i]), parseFloat(y_0)]);

                var y_1 = parseFloat((xValue[i+1]) * kValue[i]) + parseFloat(bValue[i]);
                y_1 = y_1.toFixed(2);
                data.push([parseFloat(xValue[i+1]), parseFloat(y_1)]);
            }
        }

        // LineContainer_test
        $('#LineContainer_test').highcharts({
            title: {
                text: ''
            },
            credits: {
                enabled: false
            },
            xAxis: {
                minorTickInterval: 1,
                tickInterval: 5,
            },
            yAxis: {
                title: {
                    text: null
                },
                tickInterval: 1
            },
            tooltip: {
                headerFormat: '<b>{series.name}</b><br />',
                pointFormat: 'x = {point.x}, y = {point.y}'
            },
            series: [{
                name: '标准化得分',
                data: data,
                type: 'spline',
            }]
        });
    }else{
        console.log("there is only line.");
        for(i = 0; i < bValue.length; i++){
            if((xValue[i+1]) && (xValue[i+1].toLowerCase() == "inf")){
                xValue[i+1] = 2 * xValue[i] + 80;
            }

            // two points to form a line.
            // console.log("==================");
            var y_0 = parseFloat((xValue[i]) * kValue[i]) + parseFloat(bValue[i]);
            y_0 = y_0.toFixed(2);
            data.push([parseFloat(xValue[i]), parseFloat(y_0)]);
            // console.log(parseFloat(xValue[i]));
            // console.log(parseFloat(y_0));

            var y_1 = parseFloat((xValue[i+1]) * kValue[i]) + parseFloat(bValue[i]);
            y_1 = y_1.toFixed(2);
            data.push([parseFloat(xValue[i+1]), parseFloat(y_1)]);
            // console.log(parseFloat(xValue[i+1]));
            // console.log(parseFloat(y_1));
        }

        $('#LineContainer_test').highcharts({
            chart: {
                height:263, 
                backgroundColor: '#f0f0f0'
            },
            credits: {
                enabled: false
            },
            
            title: {
                text: ' '
            },
            
            xAxis: {
                minorTickInterval: 1,
                tickInterval: 5,
            },
            
            yAxis: {
                type: 'linear',
                minorTickInterval: 0.1,
                tickInterval: 5,
                title:{
                    enabled: false,
                    text: 'y值'
                }
            },

            legend: {
                layout: 'vertical',
                backgroundColor: '#f0f0f0',
                floating: true,
                align: 'left',
                x: 30,
                verticalAlign: 'top',
                y: 30
            },

            tooltip: {
                headerFormat: '<b>{series.name}</b><br />',
                pointFormat: 'x = {point.x}, y = {point.y}'
            },
            
            series: [{            
                data,
                pointStart: 0,
                name: '指标公式图',
            }]
        });
    }
});

五、本文效果展示:

1、制定直线方程式:

2、制定多项式方程式:

3、制定直线方程式 + 多项式方程式:

六、源码分享:

1、index.html

{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html">
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=IE9,Chrome=1">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>
            定制指标公式
        </title>
        <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.css' %}">
        <link rel="stylesheet" type="text/css" href="{% static 'css/Water.css' %}">
    </head>

    <body>
        <div style="text-align: center;">
            <label style="font-size: 18px;">公式的定制:直线方程式 + 多项式方程式</label>
        </div>

        <div class="row" style="padding-top: 30px;">
            <div class="col-md-3"></div>
            <!-- 定制指标公式 - 相关信息 -->
            <div class="col-md-6">
                <div class="panel" style="border: 1px solid #e0e0e0;">
                    <div class="panel-heading">
                        <label>制定直线方程式和多项式方程式:</label>
                        <button id="btn_save" class="btn btn-sm btn-success pull-right" type="button">保存设置</button>
                    </div>
                    <div style="text-align: center;padding: 5px 0;background-color: #f0f0f0;">
                        <input id="newBtn" class="btn btn-sm btn-success" type="button" value="添加直线方程">
                        <a class="btn btn-sm btn-success" data-toggle="modal" data-target="#Add_curve" role="button">添加多项式方程</a>
                    </div>
                    <div class="panel-body">
                        <table id="IndicatorFormula_modify">
                            <tr></tr>
                        </table> 
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-3"></div>
            <div class="col-md-6">
                <div class="panel" style="border: 1px solid #e0e0e0;">
                    <div class="panel-heading">
                        <label>当前指标公式信息:</label>
                    </div>
                    <div class="panel-body">
                        <table class="" style="margin: 5px;">
                            {% for expression in expressions_list %}
                                <tr style="font-size: 15px;">
                                    <td><span class="glyphicon glyphicon-hand-right"></span> 区间:[{{ expression.x_start }} , {{ expression.x_end }}]</td>
                                    <td width="5%"></td>
                                    <td>表达式:{{expression.expression}}</td>
                                </tr>
                            {% endfor %}
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-3"></div>
            <div class="col-md-6">
                <div id="LineContainer_test"></div>
            </div>
        </div>
        <br>

        <div class="modal fade" id="Add_curve">
            <div class="modal-dialog" style="width:300px;">
                <div class="modal-content">
                    <div class="modal-body">
                        请输入曲线最高次指数:<input type="text" id="curve_num" style="width:60px;">
                        <input id="newBtn_curve" class="btn-sm btn-success pull-right" type="button" value="确定">
                    </div>
                </div>
            </div>  
        </div>

        <script type="text/javascript" src = "{% static 'js/jquery.min.js' %}" ></script>
        <script type="text/javascript" src = "{% static 'js/bootstrap.js' %}" ></script>
        <script type="text/javascript" src = "{% static 'js/highcharts.js' %}" ></script>

        <script>
            function post(URL, PARAMS) {        
                var temp = document.createElement("form");        
                temp.action = URL.toString();
                temp.method = "post";        
                temp.style.display = "none";        
                for (var x in PARAMS) {        
                  var opt = document.createElement("textarea");        
                  opt.name = x;        
                  opt.value = PARAMS[x];
                  console.log(opt.value);
                  temp.appendChild(opt);
                }        
                // alert("xx");
                document.body.appendChild(temp);        
                temp.submit();        
                return temp;
            }

            function IsNum(s)
            {
                if(s.toLowerCase() == "inf"){
                    return true;
                }

                if (s!=null && s!="")
                {
                    return !isNaN(s);
                }
                return false;
            }

            // delete line input
            function getDel(select_remove){
                $(select_remove).parent().parent().remove();
            }

            // delete curve input
            function getDelCurve(delete_num){
                delete_num = parseInt(delete_num);
                for(var i = 0; i <= delete_num; i++){
                    delete_id = "curveID_" + i.toString();
                    console.log(delete_id);
                    $("tr[id=" + delete_id + "]").remove();
                }
            }

            $(document).ready(function() {
                var count = 0;
                var line_num = [];

                // line
                $("#newBtn").bind("click", function(){
                    // console.log(this.id)
                    // console.log(count);
                    var seq = count.toString();
                    // console.log(seq);
                    line_num.push(1);
                    
                    $str = ""
                    $str += "<tr>";
                    $str += "<td>";
                    $str += "起始点: x_0 = <input id=\"x" + seq + "\" name=\"input_x\" type=\"text\" style=\"width: 40px;\">  ";
                    $str += "截止点: x_1 = <input id=\"x" + seq + "\" name=\"input_x_1\" type=\"text\" style=\"width: 40px;\">  ";
                    $str += "<td>";
                    $str += "直线斜率 = <input id=\"k" + seq + "\" name=\"input_k\" type=\"text\" style=\"width: 40px;\">";
                    $str += "</td>";
                    $str += "<td>";
                    $str += "直线偏置 = <input id=\"y" + seq + "\" name=\"input_b\" type=\"text\" style=\"width: 40px;\">";
                    $str += "</td>";
                    $str += "<td width=\"10%\"><input id=\"deleteLine_" + count + "\" class = \"btn btn-sm btn-success\" type=\"button\" value=\"删除表达式\" onClick='getDel(this)'></td>";
                    $str += "</tr>";

                    $("#IndicatorFormula_modify").append($str);

                    count++;
                }); 

                // curve
                $("#newBtn_curve").bind("click", function(){
                    var curve_num = $("#curve_num").val();
                    // console.log(curve_num);
                    if(curve_num > 0){
                        $('#Add_curve').modal('hide');

                        line_num.push(parseInt(curve_num));
                        var count_curve = 0;

                        var seq = count.toString();

                        var curve_length = curve_num;
                        var seq_curve = count_curve.toString();

                        $str = ""
                        $str += "<tr style='color:#960000;' id='curveID_0'>";
                        $str += "<td>";
                        $str += "起始点: x_0 = <input id=\"x" + seq + "\" name=\"input_x\" type=\"text\" style=\"width: 40px;\">  ";
                        $str += "截止点: x_1 = <input id=\"x" + seq + "\" name=\"input_x_1\" type=\"text\" style=\"width: 40px;\">  ";
                        $str += "<td>";
                        $str += "曲线系数 = <input id= coefficient_" + curve_length.toString() + " name=\"input_k\"" + " type=\"text\" style=\"width: 40px;\">  " + "x^" + curve_length;
                        $str += "</td><td></td>";
                        $str += "<td width=\"10%\"><input id=\"deleteLine_" + count_curve + "\" class = \"btn btn-sm btn-success\" type=\"button\" value=\"删除表达式\" onClick='getDelCurve(" + curve_num.toString() + ")'></td>";
                        $str += "</tr>";

                        $("#IndicatorFormula_modify").append($str);
                        count_curve++;

                        for(var i = count_curve; i <= curve_length; i++){
                            var seq_curve = i.toString();
                            var curveID = 'curveID_' + i.toString();
                            var curve_tr_content = "style = 'color:#960000;' id = " + curveID;
                            $str = ""
                            $str += "<tr " + curve_tr_content + ">";
                            $str += "<td></td>";
                            $str += "<td>";
                            if ((curve_length - i) != 0)
                            {
                                $str += "曲线系数 = <input id= coefficient_" + (curve_length - i).toString() + " name=\"input_k\"" + " type=\"text\" style=\"width: 40px;\">  " + "x^" + (curve_length - i);
                            }
                            else
                            {
                                $str += "曲线偏置 = <input id=\"y" + seq + "\" name=\"input_b\" type=\"text\" style=\"width: 40px;\">";
                            }
                            $str += "</td><td></td>";
                            $str += "<td></td>";
                            $str += "</tr>";

                            $("#IndicatorFormula_modify").append($str);
                        }
                    }else{
                        alert("请输入大于0的数值!");
                    }

                    count++;

                });

                $("#btn_save").bind("click", function(){
                    var x = "";
                    var b = "";
                    var k = "";
                    var x_list = document.getElementsByName("input_x");
                    var b_list = document.getElementsByName("input_b");     // y 表示偏置b
                    var k_list = document.getElementsByName("input_k");
                    var x_1_list = document.getElementsByName("input_x_1");

                    // console.log(x_list);
                    // console.log(b_list);
                    // console.log(k_list);
                    // console.log(x_1_list);

                    for (var i = 0; i < x_list.length; ++i)
                    {
                        // alert("ss");
                        if(!IsNum(x_list[i].value) || !IsNum(b_list[i].value) || !IsNum(x_1_list[i].value))
                        {
                            alert("请确认输入都为数字或者[Inf]表示无限大.");
                            return;
                        }

                        if(parseFloat(x_list[i]) > 1 || parseFloat(x_list[i]) < 0)
                        {
                            alert(x_list[i].id + "输入不合法。");
                            return;
                        }
                        if(parseFloat(b_list[i]) > 100 || parseFloat(x_list[i]) < 0)
                        {
                            alert(b_list[i].id + "输入不合法。");
                            return;
                        }
                    }

                    for (var i = 0; i < k_list.length; ++i)
                    {
                        if(!IsNum(k_list[i].value))
                        {
                            alert("请确认输入都为数字");
                            return;
                        }
                    }

                    var k_seq = 0;

                    for (var i = 0; i < x_list.length; ++i)
                    {
                        x = x + x_list[i].value + "_";
                        b = b + b_list[i].value + "_";
                        var sub_k = "";
                        for (var j = 0; j < line_num[i]; ++j)
                        {
                            sub_k = sub_k + k_list[k_seq + j].value + ";";
                            // console.log("k_seq: " + k_seq + j);
                        }
                        k_seq = k_seq + line_num[i];
                        sub_k = sub_k.substring(0, sub_k.length - 1);
                        k = k + sub_k + "_";
                    }

                    x = x + x_1_list[x_1_list.length - 1].value

                    // console.log(b_list[b_list.length - 1].value)
                    // console.log(x_list[x_list.length - 1].value)
                    // console.log()
                    // console.log(b);
                    b = b.substring(0, b.length - 1);
                    k = k.substring(0, k.length - 1);
                    // console.log(x);
                    // console.log(b);
                    // console.log(k);
                    // console.log(typeof(k));
                    post("", { x_Value: x, b_Value: b, k_Value: k });
                }); 
            });
        </script>

        <script>
            {% if x_Value and k_Value and b_Value %}
            $(function () {
                var x = "{{ x_Value }}", b = "{{ b_Value }}", k = "{{ k_Value }}";
                var i;
                var xValue = x.split("_");
                var bValue = b.split("_");
                var kValue = k.split("_");  // 未知量的系数
                // console.log(xValue);
                // console.log(bValue);
                // console.log(kValue);
                // console.log(parseFloat(xValue[2] * kValue[1]) + parseFloat(bValue[1]));
                // console.log();

                var data = new Array();
                // 判断线段的类型:
                // 1、只有直线
                // 2、有直线,又有曲线
                var has_curve = false;
                // 如果包含子串,则返回大于等于0的索引,否则返回-1
                
                for(var k = 0; k < kValue.length; k++){
                    if(kValue[k].indexOf(";")>=0){
                        has_curve = true;
                        break;
                    }
                }
                
                // has_curve == true 表示包含曲线
                if(has_curve == true){
                    console.log("there is curve.");
                    for(i = 0; i < bValue.length; i++){
                        if((xValue[i+1]) && (xValue[i+1].toLowerCase() == "inf")){
                            xValue[i+1] = 2 * xValue[i] + 40;
                        }

                        if(kValue[i].indexOf(";")>=0){
                            // 曲线处理
                            coefficient_list = kValue[i].split(";");
                            var y_0 = 0, y_1 = 0, y_2 = 0, y_3 = 0, y_4 = 0, y_5 = 0;

                            for(var k = 0; k < coefficient_list.length; k++){
                                y_0 = y_0 + parseFloat(coefficient_list[k]) * Math.pow(xValue[i], parseInt( coefficient_list.length - k));
                                y_1 = y_1 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/4), parseInt( coefficient_list.length - k));
                                y_2 = y_2 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/2), parseInt( coefficient_list.length - k));
                                y_3 = y_3 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/1.5), parseInt( coefficient_list.length - k));
                                y_4 = y_4 + parseFloat(coefficient_list[k]) * Math.pow(parseInt(xValue[i+1]/1.2), parseInt( coefficient_list.length - k));
                                y_5 = y_5 + parseFloat(coefficient_list[k]) * Math.pow(xValue[i+1], parseInt( coefficient_list.length - k));
                            }
                            y_0 = y_0 + parseFloat(bValue[i]);
                            y_0 = y_0.toFixed(2);
                            data.push([parseFloat(xValue[i]), parseFloat(y_0)]);

                            y_1 = y_1 + parseFloat(bValue[i]);
                            y_1 = y_1.toFixed(2);
                            data.push([parseFloat(parseInt(xValue[i+1]/4)), parseFloat(y_1)]);

                            y_2 = y_2 + parseFloat(bValue[i]);
                            y_2 = y_2.toFixed(2);
                            data.push([parseFloat(parseInt(xValue[i+1]/2)), parseFloat(y_2)]);

                            y_3 = y_3 + parseFloat(bValue[i]);
                            y_3 = y_3.toFixed(2);
                            data.push([parseFloat(parseInt(xValue[i+1]/1.5)), parseFloat(y_3)]);

                            y_4 = y_4 + parseFloat(bValue[i]);
                            y_4 = y_4.toFixed(2);
                            data.push([parseFloat(parseInt(xValue[i+1]/1.2)), parseFloat(y_4)]);

                            y_5 = y_5 + parseFloat(bValue[i]);
                            y_5 = y_5.toFixed(2);
                            data.push([parseFloat(xValue[i+1]), parseFloat(y_5)]);
                        }
                        else{
                            // 直线处理
                            var y_0 = parseFloat((xValue[i]) * kValue[i]) + parseFloat(bValue[i]);
                            y_0 = y_0.toFixed(2);
                            data.push([parseFloat(xValue[i]), parseFloat(y_0)]);

                            var y_1 = parseFloat((xValue[i+1]) * kValue[i]) + parseFloat(bValue[i]);
                            y_1 = y_1.toFixed(2);
                            data.push([parseFloat(xValue[i+1]), parseFloat(y_1)]);
                        }
                    }

                    // LineContainer_test
                    $('#LineContainer_test').highcharts({
                        title: {
                            text: ''
                        },
                        credits: {
                            enabled: false
                        },
                        xAxis: {
                            minorTickInterval: 1,
                            tickInterval: 5,
                        },
                        yAxis: {
                            title: {
                                text: null
                            },
                            tickInterval: 1
                        },
                        tooltip: {
                            headerFormat: '<b>{series.name}</b><br />',
                            pointFormat: 'x = {point.x}, y = {point.y}'
                        },
                        series: [{
                            name: '标准化得分',
                            data: data,
                            type: 'spline',
                        }]
                    });
                }else{
                    console.log("there is only line.");
                    for(i = 0; i < bValue.length; i++){
                        if((xValue[i+1]) && (xValue[i+1].toLowerCase() == "inf")){
                            xValue[i+1] = 2 * xValue[i] + 80;
                        }

                        // two points to form a line.
                        // console.log("==================");
                        var y_0 = parseFloat((xValue[i]) * kValue[i]) + parseFloat(bValue[i]);
                        y_0 = y_0.toFixed(2);
                        data.push([parseFloat(xValue[i]), parseFloat(y_0)]);
                        // console.log(parseFloat(xValue[i]));
                        // console.log(parseFloat(y_0));

                        var y_1 = parseFloat((xValue[i+1]) * kValue[i]) + parseFloat(bValue[i]);
                        y_1 = y_1.toFixed(2);
                        data.push([parseFloat(xValue[i+1]), parseFloat(y_1)]);
                        // console.log(parseFloat(xValue[i+1]));
                        // console.log(parseFloat(y_1));
                    }

                    $('#LineContainer_test').highcharts({
                        chart: {
                            height:263, 
                            backgroundColor: '#f0f0f0'
                        },
                        credits: {
                            enabled: false
                        },
                        
                        title: {
                            text: ' '
                        },
                        
                        xAxis: {
                            minorTickInterval: 1,
                            tickInterval: 5,
                        },
                        
                        yAxis: {
                            type: 'linear',
                            minorTickInterval: 0.1,
                            tickInterval: 5,
                            title:{
                                enabled: false,
                                text: 'y值'
                            }
                        },

                        legend: {
                            layout: 'vertical',
                            backgroundColor: '#f0f0f0',
                            floating: true,
                            align: 'left',
                            x: 30,
                            verticalAlign: 'top',
                            y: 30
                        },

                        tooltip: {
                            headerFormat: '<b>{series.name}</b><br />',
                            pointFormat: 'x = {point.x}, y = {point.y}'
                        },
                        
                        series: [{            
                            data,
                            pointStart: 0,
                            name: '指标公式图',
                        }]
                    });
                }
            });
            {% endif %}
        </script>
    </body>
</html>

2、view.py

# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from app_SettingFormula.models import *
from django.views.decorators.csrf import csrf_exempt

# Create your views here.

@csrf_exempt
def index(request):
    context = {}
    if request.method == 'POST':
        x_Value = request.POST.get('x_Value')
        k_Value = request.POST.get('k_Value')
        b_Value = request.POST.get('b_Value')

        # Formula(XValue = x_Value, KValue = k_Value, BValue = b_Value).save()
        
        print x_Value
        print b_Value
        print k_Value
        
        context['x_Value'] = x_Value
        context['k_Value'] = k_Value
        context['b_Value'] = b_Value
        if x_Value and k_Value and b_Value:
        	context['expressions_list'] = get_IndicatorFormula_expression(x_Value, k_Value, b_Value)
        else:
        	print("x_Value or k_Value or b_Value exist null")

    return render(request, 'index.html', context)

def get_IndicatorFormula_expression(x_Value, k_Value, b_Value):
    X_list = x_Value.strip().split('_')
    K_list = k_Value.strip().split('_')
    B_list = b_Value.strip().split('_')

    # print "---"
    # print "X_list",X_list
    # print "B_list",B_list

    i = 0
    expressions_list = []

    # line and curve
    # find()函数找不到时返回为-1。
    for k in K_list:
        # print k
        expression = ""
        if k.find(";") == -1:
            print "=== line ==="
            if K_list[i]=='0':
                expression = "y = " + B_list[i]
            elif K_list[i]=='1':
                if (B_list[i]).find("-") == -1:
                    if B_list[i]==0:
                        expression = "y = x"
                    else:
                        expression = "y = x + " + B_list[i]
                else:
                    expression = "y = x " + B_list[i]
            else:
                if (B_list[i]).find("-") == -1:
                    if B_list[i]==0:
                        expression = "y = " + K_list[i] + "x"
                    else:
                        expression = "y = " + K_list[i] + "x + " + B_list[i]
                else:
                    expression = "y = " + K_list[i] + "x " + B_list[i]
        else:
            print "=== curve ==="
            curve_list = k.strip().split(';')
            j = 0
            curve_len = len(curve_list)
            print "curve_len = ",curve_len
            for j in range(curve_len):
                # exponent: 指数
                # curve_list[j]: 系数
                exponent = str(curve_len - j)
                print "exponent = ",exponent
                if curve_list[j] == "0":
                    expression = expression
                elif curve_list[j] == "1":
                    if exponent == "1":
                        expression = expression + " + x"
                    else:
                        expression = expression + " + " + "x^" + exponent
                elif curve_list[j] == "-1":
                    if exponent == "1":
                        expression = expression + " - x "
                    else:
                        expression = expression + " - x^" + exponent
                # coefficient > 0 except 1
                elif (curve_list[j]).find("-") == -1:
                    if exponent == "1":
                        # the begin position.
                        if j == 0:
                            expression = curve_list[j] + "x"
                        else:
                            expression = expression + " + " + curve_list[j] + "x"
                    else:
                        if j == 0:
                            expression = curve_list[j] + "x^" + exponent
                        else:
                            expression = expression + " + " + curve_list[j] + "x^" + exponent
                # coefficient < 0 except -1
                else:
                    if exponent == "1":
                        expression = expression + curve_list[j] + "x"
                    else:
                        expression = expression + curve_list[j] + "x^" + exponent
                        
            if (B_list[i]).find("-") == -1:
                expression = "y = " + expression + " + " + B_list[i]
            else:
                expression = "y = " + expression + B_list[i]
        expressions_list.append(display_expression(X_list[i], X_list[i+1], expression))

        i = i + 1

    return expressions_list


### class ### 
class display_expression:
	def __init__(self, x_start, x_end, expression):
		self.x_start = x_start
		self.x_end = x_end
		self.expression = expression

完整工程源码,请到这里下载:

1、【CSDN博客资源】http://download.csdn.net/detail/houchaoqun_xmu/9834798 

2、【Github】https://github.com/Houchaoqun/Daily-Coding/tree/master/web_development/SettingFormula_django_highcharts_js

注:Github的代码最新,而且有进展会持续更新。

七、总结:

本文基于【django + js + highcharts】实现了普通直线方程式和曲线方程式的制定,包括:

1、用户根据自身需求添加普通直线方程式或曲线方程式,弹出对应的输入框。

2、用户根据自身需求可删除上一步添加的输入框。

3、设计相应的数据结构,根据用户所输入的方程式信息进行解析,后台使用python语言进行解析,返回对应的区间和方程式。

4、基于highcharts绘制方程式对应的坐标系,前端使用js进行解析,根据方程式的类型(普通直线或者多项式方程式)做相应的处理。

 

本文目前只实现了普通直线方程式和曲线方程式的处理,尚未扩展到一般的曲线,如今后有这方面的需求,实现后会再补充整理分享给大家。

值得一提的是,本文的方法目前仍存在如下缺陷:

1、对highcharts插件不够熟悉,绘制多项式曲线的时候,效果不是很好,本文采用的方法是使用【type: 'spline'】,在相应的区间内绘制多个点,构成对应的曲线,如下图所示,多项式方程式【y = 2x^3 + 0】在区间[0, 100]内,绘制了20个点构成了对应的曲线。

上图的效果还不错,但是,细心的同学可以注意到区间 [0, 25] 中,由于没有绘制多个点,导致不能更好的逼近曲线,代码中有详细解释这个问题。此外,这个方法在“仅有多项式方程式”的情况表现良好,但是,在混合方程式中的表现就不尽人意,比如“直线+多项式+直线”,如下图所示,多项式曲线部分的效果不是很好,可能是因为图不够大,但这不是能够接受的理由,后续有机会再继续完善。

2、按照如下过程会有bug:

先添加直线方程的输入框 --> 再添加曲线方程的输入框(如:最高指数幂为3) --> 删除直线方程的输入框 --> 输入曲线的相关参数(如:y = -2x^3 + x^2 -1),此时会出现问题:出来的是一条直线,因为一开始删除的直线方程输入框的原因,导致系统把当前的曲线识别为直线的输入框。

=== 解决bug:

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值