分享一个本人设计的 行为定义引擎 c#版

本文介绍了一个C#实现的行为定义引擎,旨在解决UI层用户操作复杂、事件多的问题。通过统一的输入输出方法签名,实现小粒度方法调用的便捷性和灵活性。设计包括构建XML方法树并执行,已在实际项目中应用并取得良好效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

行为定义引擎  

设计原因: UI层 用户操作复杂 ,事件繁多,业务繁琐,控制代码粒度如果太大,重复代码太多,灵活性差,如果降低控制代码粒度, 重用性好,灵活性好,但是,方法太多,调用麻烦

设计目的:使用小粒度方法,达到调用方便灵活直观的目的

设计思路:使用通一输入输出方法签名      Action<Dictionary<string, object>, Action<object>, Action<object>> func = null;    Dictionary<string, object> 是输入数据,第一个 Action<object> 是 成功后 执行方法,第二个  Action<object> 是失败后执行方法,

所有方法都使用这一签名


先构建XML状的方法树 ,引擎+模板

然后运行


这一行为定义引擎已在项目中使用 ,效果不错



行为定义引擎 代码如下

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Linq;


namespace LFRT5.clint.myControls
{
    public class pageDo
    {






        public string name { get; set; }
        public string xmlstring { get; set; }


        //string neweve { get; set; }
        //string newobj { get; set; }
      //  List<string[]> neweve = new List<string[]>();


        XDocument doc = null;


        public void eve(string objname, string evename, Func<string, string, Action<Dictionary<string, object>, Action<object>, Action<object>>> getfunc)
        {
            //try
            //{
            pageDoMode m = new pageDoMode();
             doc = XDocument.Parse(xmlstring);
            var e = geteveEle(objname, evename, doc);
           
            m = createEve(getfunc, m, e);
            if (m != null) m.dofun();
            //if (neweve.Count > 0)
            //{
            //    var newevetemp = neweve;
            //    neweve = new List<string[]>();
            //    foreach (var item in newevetemp)
            //    {
            //        var ev = item[0];
            //        var ob = item[1];
            //        eve(ob, ev, getfunc);
            //    }


            //}


            //}
            //catch (Exception ee)
            //{


            //    MessageBox.Show(ee.Message);
            //}




        }


        private XElement geteveEle(string objname, string evename, XDocument doc)
        {
            var e = doc.Root.Element(name).Element(objname).Element(evename);
            if (e == null)
            {


                e = doc.Root.Element("通用").Element(objname).Element(evename);
                return null;
            }
            return e;
        }


        private pageDoMode createEve(Func<string, string, Action<Dictionary<string, object>, Action<object>, Action<object>>> getfunc, pageDoMode m, XElement xmlread)
        {


            var e = xmlread;
            if (e.Attribute("type") != null && e.Attribute("type").Value == "neweve")
            {
               // string[] strs = new string[] { e.Name.LocalName, e.Attribute("objname").Value };
               // neweve.Add(strs);
               // return null;


                 e = geteveEle(e.Attribute("objname").Value, e.Name.LocalName, doc);
            }


            {
                Action<Dictionary<string, object>, Action<object>, Action<object>> fun = null;
                if (e.Attribute("type") != null && e.Attribute("type").Value == "eve")
                {
                    fun = (invalue, ok, err) => { ok(System.DBNull.Value); };
                }
                else
                    fun = getfunc(e.Attribute("objname").Value, e.Name.LocalName);
                if (fun == null) throw new Exception("fun is null " + e.Name.LocalName);
                m.func = fun;


                var ns = e.Nodes();
                foreach (var item in ns)
                {
                    var el = item as XElement;
                    if (el == null) continue;
                    var n = el.Name.LocalName;
                    switch (n)
                    {
                        case "inv":
                            var tns2 = el.Nodes();
                            foreach (var item1 in tns2)
                            {
                                var el1 = item1 as XText;
                                if (el1 == null || string.IsNullOrEmpty(el1.Value)) continue;
                                m.invalue.Add(el.Attribute("vname").Value, el1.Value);
                            }
                            break;
                        case "in":
                            var tns3 = el.Nodes();
                            foreach (var item1 in tns3)
                            {
                                var el1 = item1 as XElement;
                                if (el1 == null) continue;
                                var f = getfunc(el1.Attribute("objname").Value, el1.Name.LocalName);
                                if (f == null) continue;
                                m.GetValue.Add(el.Attribute("vname").Value, f);
                            }


                            break;
                        case "ok":
                            var tns = el.Nodes();
                            foreach (var item1 in tns)
                            {
                                var el1 = item1 as XElement;
                                if (el1 == null) continue;
                                var okm = createEve(getfunc, new pageDoMode(), el1);
                                if (okm != null) m.ok.Add(okm);
                            }


                            break;
                        case "err":
                            var tns1 = el.Nodes();
                            foreach (var item1 in tns1)
                            {
                                var el1 = item1 as XElement;
                                if (el1 == null) continue;
                                var errm = createEve(getfunc, new pageDoMode(), el1);
                                if (errm != null) m.err.Add(errm);
                            }
                            break;
                    }
                }




                //   fun(ok, err);
            }
            return m;
        }
    }


    public class pageDoMode
    {
        public Dictionary<string, Action<Dictionary<string, object>, Action<object>, Action<object>>> GetValue = new Dictionary<string, Action<Dictionary<string, object>, Action<object>, Action<object>>>();  //new List<Action<List<object>, Action<object>, Action<object>>>();
        //  public List<object> invalue = new List<object>();
        public Dictionary<string, object> invalue = new Dictionary<string, object>();
        public List<pageDoMode> ok = new List<pageDoMode>();
        public List<pageDoMode> err = new List<pageDoMode>();
        public Action<Dictionary<string, object>, Action<object>, Action<object>> func = null;
        public void dofun()
        {


            if (GetValue != null)
            {
                foreach (var item in GetValue)
                {
                    object obj = null;
                    item.Value(null, (o) => { obj = o; }, null);
                    if (!(obj is DBNull)) invalue.Add(item.Key, obj);




                }
            }


            func(invalue,
                (o) =>
                {
                    if (ok == null || ok.Count == 0) return;
                    ok.ForEach((c) =>
                    {
                        if (!(o is DBNull)) { if(c.invalue.ContainsKey("ok"))c.invalue.Remove("ok");  c.invalue.Add("ok", o); }
                        c.dofun();
                    });
                },
                (o) =>
                {
                    if (err == null || err.Count == 0) return;
                    err.ForEach((c) => { c.invalue.Add("error", o); c.dofun(); });
                });


        }


    }
}


行为定义模板XML


<?xml version="1.0" encoding="utf-8" ?>
<pagedo>
<员工管理>
<页面>
<页面初始化 type="eve">
<ok>
<datagrid添加资源 objname="页面">
<inv vname="dts">sel,v04,view03,_v06,v06</inv>
</datagrid添加资源>
<Fun_str_int2_m15 objname="通用数据服务">
<inv vname="command">获得人员列</inv>
<ok>
<datagrid列绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m15>


<Fun_str_int2_m5 objname="通用数据服务">
<inv vname="command">获得功能信息</inv>
<ok>
<功能绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m5>
<查询数据 type="neweve" objname="页面" />
<部门数据绑定 type="neweve" objname="页面" />
<Fun_str_int2_m5 objname="通用数据服务">
<inv vname="command">获得仅部门信息</inv>

<ok>
<datagrid_comdata数据绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m5>
</ok>
</页面初始化>
<部门数据绑定 type="eve">
<ok>
<Fun_str_ns_m5 objname="通用数据服务">
<inv vname="command">获得部门信息</inv>
<ok>
<mytreeview数据绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_ns_m5>
</ok>
</部门数据绑定>
<部门改变  type="eve">
<ok>
<查询数据 type="neweve" objname="页面" />
</ok>
</部门改变 >
<查询数据 type="eve">
<ok>
<Fun_str_int objname="通用数据服务">
<inv vname="command">获得人员数量信息</inv>
<in vname="filters">
<获得查询字符串 objname="页面"/>
</in>


<ok>
<datagrid数量绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int>
</ok>
</查询数据>
<datagrid翻页 type="eve">
<ok>
<人员查询 type="neweve" objname="页面" />
</ok>
</datagrid翻页>
<人员查询  type="eve">
<ok>
<Fun_str_int2_m20 objname="通用数据服务">
<inv vname="command">获得人员数据信息</inv>
<in vname="filters">
<获得查询字符串 objname="页面"/>
</in>
<in vname="start">
<datagrid起始行号 objname="页面"/>
</in>
<in vname="end">
<datagrid截至行号 objname="页面"/>
</in>
<ok>
<datagrid数据绑定 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m20>
</ok>
</人员查询>

<关闭部门编辑窗口 type="eve">
<ok>
<关闭部门编辑窗口 objname="页面"/>
</ok>
</关闭部门编辑窗口>
<部门编辑确认 type="eve">
<ok>
<Fun_m5_int objname="通用数据服务">
<inv vname="command">部门数据保存</inv>
<in vname="m">
<获得部门编辑数据 objname="页面"/>
</in>
<ok>
<部门数据绑定 type="neweve" objname="页面" />
<关闭部门编辑窗口 type="neweve" objname="页面" />




</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_m5_int>
</ok>
</部门编辑确认>


</页面>
<员工控制>
<按钮只读 type="eve">
<ok>
<按钮控制 objname="员工控制">
<inv vname="name">*</inv>
<inv vname="enble">true</inv>
</按钮控制>
<按钮控制 objname="员工控制">
<inv vname="name">撤销,保存</inv>
<inv vname="enble">false</inv>
</按钮控制>


</ok>
</按钮只读>
<按钮编辑 type="eve">
<ok>
<按钮控制 objname="员工控制">
<inv vname="name">*</inv>
<inv vname="enble">true</inv>
</按钮控制>
<按钮控制 objname="员工控制">
<inv vname="name">新建,删除,修改</inv>
<inv vname="enble">false</inv>
</按钮控制>


</ok>
</按钮编辑>
<初始化完成 type="eve">
<ok>
<按钮只读 type="neweve" objname="员工控制" />
</ok>
</初始化完成>
<新建  type="eve">
<ok>
<按钮编辑 type="neweve" objname="员工控制" />
<Fun_str_m20 objname="通用数据服务">
<inv vname="command">新建人员数据</inv>
<in vname="m">
<获得人员编辑数据 objname="页面"/>
</in>
<ok>
<datagrid添加行 objname="页面"/>


</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_m20>
<datagrid只读 objname="页面">
<inv vname="IsReadOnly">false</inv>
</datagrid只读>
</ok>
</新建>
<修改  type="eve">
<ok>
<按钮编辑 type="neweve" objname="员工控制" />
<datagrid只读 objname="页面">
<inv vname="IsReadOnly">false</inv>
</datagrid只读>
</ok>
</修改>
<删除  type="eve">
<ok>
<datagrid删除询问>
<ok>
<Fun_m20s_int objname="通用数据服务">
<inv vname="command">人员数据删除</inv>
<in vname="m">
<获得datagrid勾选行 objname="页面"/>
</in>
<ok>

<人员查询 type="neweve" objname="页面"/>

</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_m20s_int>
</ok>
</datagrid删除询问>
</ok>
</删除>
<撤销  type="eve">
<ok>
<按钮只读 type="neweve" objname="员工控制" />
<人员查询 type="neweve" objname="页面"/>
<datagrid只读 objname="页面">
<inv vname="IsReadOnly">true</inv>
</datagrid只读>
</ok>
</撤销>
<保存  type="eve">
<ok>
<Fun_m20s_int objname="通用数据服务">
<inv vname="command">人员数据保存</inv>
<in vname="m">
<获得datagrid编辑行 objname="页面"/>
</in>
<ok>
<按钮只读 type="neweve" objname="员工控制" />
<人员查询 type="neweve" objname="页面"/>
<datagrid只读 objname="页面">
<inv vname="IsReadOnly">true</inv>
</datagrid只读>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_m20s_int>


</ok>
</保存>
<EXCEL type="eve">
<ok>
<Fun_str_int2_m20 objname="通用数据服务">
<inv vname="command">获得人员数据信息</inv>
<in vname="filters">
<获得查询字符串 objname="页面"/>
</in>


<ok>
<导出到EXCEL objname="页面">
<in vname="columns">
<获得datagrid列  objname="页面"></获得datagrid列>
</in>
</导出到EXCEL>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m20>
</ok>
</EXCEL>
</员工控制>
<部门控制>
<初始化完成 type="eve">


</初始化完成>
<新建部门 type="eve">
<ok>
<Fun_str_int2_m15 objname="通用数据服务">
<inv vname="command">获得部门列</inv>
<ok>
<部门新建 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m15>
</ok>
</新建部门>
<删除部门 type="eve">
<ok>
<部门删除询问  objname="页面">
<ok>
<Fun_m5_int objname="通用数据服务">
<inv vname="command">部门数据删除</inv>
<in vname="m">
<获得部门选择数据 objname="页面"/>
</in>
<ok>
<部门数据绑定 type="neweve" objname="页面" />




</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_m5_int>
</ok>
</部门删除询问>
</ok>
</删除部门>
<机构修改 type="eve">
<ok>
<Fun_str_int2_m15 objname="通用数据服务">
<inv vname="command">获得部门列</inv>
<ok>
<部门修改 objname="页面"/>
</ok>
<err>
<消息 objname="页面"/>
</err>
</Fun_str_int2_m15>
</ok>
</机构修改>


</部门控制>
</员工管理>


</pagedo>



使用代码示例如下


   public pageDo pagedoobj
        {
            get
           ;
            set
            ;
        }

  pagedoobj.xmlstring = xml;

 pagedoobj.name = name;
  pagedoobj.eve("页面", "页面初始化", getFun);



        public Action<Dictionary<string, object>, Action<object>, Action<object>> getFun(string objname, string evename)
        {
            Action<Dictionary<string, object>, Action<object>, Action<object>> func = null;
            switch (objname)
            {
                case "页面":
                default :
                    switch (evename)
                    {
                        case "datagrid添加资源":
                            func = (invs, ok, err) =>
                          {
                              var dtstr = invs["dts"] as string;
                              var dtstrs = dtstr.Split(',');
                              foreach (var item in dtstrs)
                              {
                                  if (mainpage.Resources.Contains(item))
                                      mainpage.mydatagrid1.myDataTemplate.Add(item, mainpage.Resources[item]);
                              }




                          };
                            break;
                        case "mytreeview数据绑定":
                            func = (invs, ok, err) =>
                            {


                                var bmdata = invs["ok"];
                                if (bmdata == null) return;
                                var obj = mainpage.myTreeView_bm.treeView1.DataContext;
                                mainpage.myTreeView_bm.treeView1.DataContext = bmdata;
                                if (obj != null) mainpage.myTreeView_bm.treeView1.OnApplyTemplate();
                                //  mainpage.myTreeView_bm.treeView1.DataContext = bmdata;
                                if (ok != null) ok(DBNull.Value);
                            };


                            break;
                        case "功能绑定":
                            func = (invs, ok, err) =>
                            {


                                var data = invs["ok"];
                                if (data == null) return;
                                LFRT5.clint.util.initMyTabButtons(mainpage.tabButtons1, data as List<Model5>);
                                LFRT5.clint.util.initMyTabButtons(mainpage.tabButtons3, data as List<Model5>);
                                if (ok != null) ok(DBNull.Value);
                            };


                            break;
                        case "datagrid只读":
                            func = (invs, ok, err) =>
                            {
                                var data = Convert.ToBoolean(invs["IsReadOnly"]);
                                mainpage.mydatagrid1.dataGrid1.IsReadOnly = data;
                                if (ok != null) ok(DBNull.Value);
                            };
                            break;
                        case "datagrid列绑定":
                            func = (invs, ok, err) =>
                            {


                                var data = invs["ok"];
                                if (data == null) return;
                                mainpage.mydatagrid1.GridAddColumn(data as List<Model15>);
                                if (ok != null) ok(DBNull.Value);
                            };


                            break;
                        case "获得datagrid列":
                            func = (invs, ok, err) =>
                            {


                                if (ok != null) ok(mainpage.mydatagrid1.gridColumns);
                            };


                            break;
                        case "datagrid数量绑定":


                            func = (invs, ok, err) =>
                            {


                                var data = invs["ok"];
                                if (data == null) return;
                                mainpage.mydatagrid1.customDataPager1.DataCount = (int)data;
                                if (ok != null) ok(DBNull.Value);
                            };
                            break;
                        case "datagrid数据绑定":
                            func = (invs, ok, err) =>
                            {
                                var data = invs["ok"];
                                if (data == null) return;
                                mainpage.mydatagrid1.dataGrid1.DataContext = data;
                                var ms = mainpage.mydatagrid1.dataGrid1.DataContext as System.Collections.IList;
                                foreach (var item in ms)
                                {
                                    dynamic m = item;
                                    m.vc01 = "false";
                                }
                                if (ok != null) ok(DBNull.Value);
                            };
                            break;
                        case "datagrid_comdata数据绑定":
                            func = (invs, ok, err) =>
                           {
                               var data = invs["ok"];
                               if (data == null) return;
                               var collectionView = mainpage.Resources["comdata"] as System.Windows.Data.CollectionViewSource;
                               collectionView.Source = data;
                               if (ok != null) ok(DBNull.Value);
                           };
                        break;
                        case "获得datagrid勾选行":
                            func = (invs, ok, err) =>
                            {
                                var ms = mainpage.mydatagrid1.dataGrid1.DataContext as System.Collections.IList;
                                var ds = new List<object>();
                                foreach (var item in ms)
                                {
                                    dynamic d = item;
                                    if (Convert.ToBoolean(d.vc01))
                                    {
                                        ds.Add(item);
                                    }
                                }
                                if (ok != null) ok(ds);
                            };
                            break;
                        case "获得datagrid编辑行":
                            func = (invs, ok, err) =>
                            {
                                var ms = mainpage.mydatagrid1.dataGrid1.DataContext as System.Collections.IList;
                                var ds = new List<object>();
                                foreach (var item in ms)
                                {
                                    dynamic d = item;
                                    if (Convert.ToInt32(d.id)<0)
                                    {
                                        ds.Add(item);
                                    }
                                }
                                if (ok != null) ok(ds);
                            };
                            break;
                        case "datagrid添加行":
                            func = (invs, ok, err) =>
                            {
                                var data = invs["ok"];
                                if (data == null) return;
                                var ms = mainpage.mydatagrid1.dataGrid1.DataContext as System.Collections.IList;
                                ms.Insert(0, data);
                                mainpage.mydatagrid1.dataGrid1.OnApplyTemplate();
                                if (ok != null) ok(DBNull.Value);
                            };
                            break;
                        case "datagrid起始行号":
                            func = (invs, ok, err) =>
                            {
                                if (ok != null) ok(mainpage.mydatagrid1.customDataPager1.rowStart);
                            };
                            break;
                        case "datagrid截至行号":
                            func = (invs, ok, err) =>
                            {
                                if (ok != null) ok(mainpage.mydatagrid1.customDataPager1.rowEnd);
                            };
                            break;
                        case "datagrid删除询问":
                            func = (invs, ok, err) =>
                            {
                                if (util.MessageBoxShow(mainwin, "确定删除数据么?", "删除", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                                {
                                  if (ok != null) ok(DBNull.Value);
                                }
                              
                            };
                            break;
                      
                        case "获得查询字符串":
                            func = (invs, ok, err) =>
                            {
                                string str = "";
                                var n = mainpage.myTreeView_bm.treeView1.SelectedItem as Node;
                                if (n != null && !string.IsNullOrEmpty(n.Text))
                                {
                                    str += "view01=" + n.Text + "|view03=" + n.Text;
                                }
                                var m = mainpage.dataForm11.CurrentItem as LFRT5.db.models.Model5;
                                if (m != null && !string.IsNullOrEmpty(m.v01))
                                {
                                    if (!string.IsNullOrEmpty(str)) str += "|";
                                    str += "v01^" + m.v01 + "|v02^" + m.v01 + "|v03^" + m.v01 + "|v04^" + m.v01 + "|v05^" + m.v01;
                                }


                                if (ok != null) ok(str);
                            };
                            break;
                        case "部门修改":
                            func = (invs, ok, err) =>
                           {
                               var columns = invs["ok"];
                               ShowWindow_bumen("修改", evename, columns);
                               if (ok != null) ok(wbumen);
                           };
                            break;
                        case "部门新建":
                            func = (invs, ok, err) =>
                            {
                                var columns = invs["ok"];
                                ShowWindow_bumen("新建", evename, columns);
                                if (ok != null) ok(wbumen);
                            };
                            break;
                        case "关闭部门编辑窗口":
                            func = (invs, ok, err) =>
                           {
                               mainGrid.Children.Remove(wbumen);
                               wbumen = null;
                               if (ok != null) ok(DBNull.Value);
                           };
                            break;
                        case "部门删除询问":
                            func = (invs, ok, err) =>
                            {
                                var b = bumenDeleteDataTel();
                                if (!b) return;
                                if (ok != null) ok(DBNull.Value);
                            };
                            break;
                        case "获得部门GUID":
                            func = (invs, ok, err) =>
                            {
                                var guid = ((ObservableCollection<Node>)(mainpage.myTreeView_bm.treeView1.DataContext))[0].model.guid;
                                if (ok != null) ok(guid);


                            };
                            break;
                        case "获得部门编辑数据":
                            func = (invs, ok, err) =>
                            {


                                var d = (wbumen.dataForm11.DataContext as List<Model15>)[0];
                                if (string.IsNullOrEmpty(d.v02)) d.v02 = ((ObservableCollection<Node>)(mainpage.myTreeView_bm.treeView1.DataContext))[0].model.guid;
                                Model5 m = new Model5();
                                util.Tconvert<Model5, Model15>(ref m, d);
                                if (ok != null) ok(m);
                            };
                            break;
                        case "获得部门选择数据":
                            func = (invs, ok, err) =>
                            {


                                var d = ((Node)(mainpage.myTreeView_bm.treeView1.SelectedItem)).model;
                                Model5 m = new Model5();
                                util.Tconvert<Model5, Model15>(ref m, d);
                                if (ok != null) ok(m);
                            };
                            break;
                        case "消息":
                            func = (invalue, ok, err) => { util.MessageBoxShow(mainwin, invalue["error"] as string); };
                            break;
                        case "导出到EXCEL":
                            func = (invalue, ok, err) => {
                                var columns = invalue["columns"] as List<Model15> ;
                                var ds = invalue["ok"] as System.Collections.IList;
                                var newds = new List<object>();
                                foreach (var item in ds)
                                {
                                    newds.Add(item);
                                }
                                util.toExcel(columns, newds);
                                
                            };
                            break;
                    }
                    break;




                case "员工控制":
                    func = mainpage.tabButtons1.getFunc(evename);
                    break;
                case "部门控制":
                    func = mainpage.tabButtons3.getFunc(evename);
                    break;
                case "通用数据服务":
                    func = svc.getFunc(evename);
                    break;
           


                    return null;


            }
            return func;
        }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值