ExtJs之GridPanel、FormPanel综合篇

今天我们一块看一下GridPanel和FormPanel的另外一些知识。在这一篇文章中我觉得更多的是FromPanel的应用,虽然前面我们单独说了FromPanel布局及其相关控件,但是关于FromPanel的提交和加载一直没有说。在这一篇文章中我们着重说一下FromPanel的加载与提交,以及如何将FormPanel与TabPanel结合起来等。例子要实现的功能:显示商品信息并且支持分页和搜索;单击某商品弹出相关信息(包括供货商和种类信息);在弹出窗口中可以自动加载相关信息并且可以修改提交。

温故而知新

由于这一篇文章是结合了几种控件来阐述的,GridPanel部分是在上一篇"ExtJs之GridPanel篇"之上进行修改的,除了添加其双击事件等代码外其他的几乎完全一样。但是作为一个完整的例子我觉得还是把代码放出了,不明白的朋友可以参考上一篇关于GridPanel的文章。下面是例子中GridPanel功能的后台代码,前台代码我们放在下面和FromPanel一块说:

using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Web.Script.Serialization; using System.Collections.Generic; using System.Text; using Cmj.MyData; namespace GridPanel { public partial class _Default : System.Web.UI.Page { DBHelper dbHelper = new DBHelper(); int count; protected void Page_Load(object sender, EventArgs e) { int pageSize=10; int start=0; Session["categoryID"] = ""; Session["productName"] = ""; if (!string.IsNullOrEmpty(Request["limit"])) { pageSize = int.Parse(Request["limit"]); } if (!string.IsNullOrEmpty(Request["start"])) { start = int.Parse(Request["start"]); } if (start==0 && Request["categoryName"] != null && Request["productName"]!=null)//说明是查询而不是翻页 { Session["categoryID"] = Request["categoryName"]; Session["productName"] = Request["productName"]; } count = GetCount(Session["categoryID"].ToString(), Session["productName"].ToString()); Response.Write(GetJson(GetDataTabel(GetSql(Session["categoryID"].ToString(), Session["productName"].ToString()), pageSize, start), Session["categoryID"].ToString(), Session["productName"].ToString())); Response.End(); } private string GetSql(string categoryID,string productName) { string sql = "SELECT dbo.Products.ProductID, dbo.Products.ProductName,dbo.Categories.CategoryName,dbo.Products.UnitPrice,dbo.Products.Discontinued,dbo.Products.QuantityPerUnit,dbo.Suppliers.CompanyName FROM dbo.Products INNER JOIN dbo.Categories ON dbo.Products.CategoryID = dbo.Categories.CategoryID" + " INNER JOIN dbo.Suppliers ON dbo.Suppliers.SupplierID=dbo.Products.SupplierID "; if (categoryID != "all") { sql += "WHERE dbo.Categories.CategoryID='" + categoryID + "'"; } if(productName!=string.Empty) { sql+= " AND dbo.Products.ProductName like '%" + productName + "%'"; } return sql; } private int GetCount(string categoryID,string productName) { string sql = "SELECT dbo.Products.ProductID FROM dbo.Products INNER JOIN dbo.Categories ON dbo.Products.CategoryID = dbo.Categories.CategoryID" + " INNER JOIN dbo.Suppliers ON dbo.Suppliers.SupplierID=dbo.Products.SupplierID "; if (categoryID != "all") { sql += "WHERE dbo.Categories.CategoryID='" + categoryID + "'"; } if (productName != string.Empty) { sql += " AND dbo.Products.ProductName like '%" + productName + "%'"; } int count = dbHelper.GetDataTable(CommandType.Text, sql).Rows.Count; return count; } private DataTable GetDataTabel(string sql, int pageSize, int start) { PagingSQLHelperExtend psHelper = new PagingSQLHelperExtend(sql,"ProductID", "asc", pageSize); int currentPageIndex=start/pageSize+1; return dbHelper.GetDataTable(CommandType.Text, psHelper.GetSQL(currentPageIndex)); } private string GetJson(DataTable dt,string categoryID,string productName) { List<Product> customers = new List<Product>(); Product customer; foreach (DataRow dr in dt.Rows) { customer = new Product(); customer.ProductID = dr["ProductID"].ToString(); customer.ProductName = dr["ProductName"].ToString(); customer.CategoryName = dr["CategoryName"].ToString(); customer.UnitPrice = double.Parse(dr["UnitPrice"].ToString()); if (dr["Discontinued"].ToString() == "True") { customer.Discontinued = "是"; } else { customer.Discontinued = "否"; } customer.QuantityPerUnit = dr["QuantityPerUnit"].ToString(); customer.CompanyName = dr["CompanyName"].ToString(); customers.Add(customer); } JavaScriptSerializer jsSerializer = new JavaScriptSerializer(); StringBuilder sb = new StringBuilder("{ totalProperty:"); sb.Append(count); sb.Append(",root:"); sb.Append(jsSerializer.Serialize(customers)); sb.Append("}"); return sb.ToString(); } } }

控件结合使用

下面我们看一下整个例子的前提代码。好了,先看一下前台的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!--<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">--> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>GridPanel</title> <link href="ext/resources/css/ext-all.css" mce_href="ext/resources/css/ext-all.css" rel="stylesheet" type="text/css" /> <mce:script src="ext/adapter/ext/ext-base.js" mce_src="ext/adapter/ext/ext-base.js" type="text/javascript"></mce:script> <mce:script src="ext/ext-all.js" mce_src="ext/ext-all.js" type="text/javascript"></mce:script> <mce:script type="text/javascript"><!-- Ext.onReady(function(){ var dtCategory=[ ['all','所有种类'], ['1','Beverages'], ['2','Condiments'], ['3','Confections'], ['4','Dairy Products'], ['5','Grains/Cereals'], ['6','Meat/Poultry '], ['7','Produce'], ['8','Seafood'] ]; var stCategory=new Ext.data.SimpleStore({ fields:['value','text'], data:dtCategory }); var cbCategory=new Ext.form.ComboBox({ id:"cbCategory", store:stCategory, displayField:"text", valueField:"value", typeAhead:true, mode:"local", triggerAction:"all", emptyText:"请选择商品种类...", editable:false, allowBlank:false, blankText:"商品种类必须选择", autoSelect:true, selectOnFoucus:true, value:'', dfval:'' }); cbCategory.setValue("all"); var tfName=new Ext.form.TextField({ id:'tfName' }); var btnSearch=new Ext.Button({ id:'btnSearch', iconCls:'btn_search', text:'搜索', handler:function(){ stProduct.load({params:{start:0,limit:10,categoryName:Ext.getCmp("cbCategory").getValue(),productName:Ext.getCmp("tfName").getValue()}}); } }); var btnHelp=new Ext.Button({ text:'帮助', iconCls:'btn_help' }) var tb=new Ext.Toolbar({ id:'tb', items:[ '商品种类:', cbCategory, '-', '商品名称:', tfName, btnSearch, '->', btnHelp ] }); var pnNorth=new Ext.Panel({ id:'pnNorth', region:'north', autoHeight:true, items:[ tb ] }); var url="Default.aspx"; var stProduct=new Ext.data.Store({ id:"st", proxy:new Ext.data.HttpProxy({url:url}), reader:new Ext.data.JsonReader({totalProperty:"totalProperty",root:"root",fields:[{name:"ProductID"},{name:"ProductName"},{name:"CategoryName"},{name:'UnitPrice'},{name:'Discontinued'},{name:'QuantityPerUnit'},{name:'CompanyName'}] })//ProductID作为隐藏列,不显示在gridpanel中 }); stProduct.load({params:{start:0,limit:10,categoryName:Ext.getCmp("cbCategory").getValue(),productName:Ext.getCmp("tfName").getValue()}}); var cmProduct=new Ext.grid.ColumnModel([ new Ext.grid.RowNumberer(), {header:"产品名称",dataIndex:"ProductName",sortable:true}, {header:"产品种类",dataIndex:"CategoryName",sortable:true}, {header:"单价",dataIndex:"UnitPrice",sortable:true}, {header:"是否停产",dataIndex:"Discontinued",sortable:true}, {header:"规格",dataIndex:"QuantityPerUnit",sortable:true}, {header:"供货商",dataIndex:"CompanyName",sortable:true} ]); var pgtbProduct=new Ext.PagingToolbar({ id:"pgtbProduct", displayInfo:true, emptyMsg:"没有数据要显示!", displayMsg:"当前为第{0}--{1}条,共{2}条数据", store:stProduct, pageSize:10 }); var grdProduct=new Ext.grid.GridPanel({ id:"grdProduct", title:"商品信息", cm:cmProduct, store:stProduct, autoWidth:true, selModel:new Ext.grid.RowSelectionModel({single:true}), height: screen.availHeight-190, frame: true, pageSize:20, bbar:pgtbProduct, //autoExpandColumn:6, loadMask:true, viewConfig:{ forceFit:true } }); var stSupplier = new Ext.data.Store({ id: "stSupplier", autoLoad:true, proxy: new Ext.data.HttpProxy({ url: "ProductInfo.aspx?type=getSupplierInfo" }), reader: new Ext.data.JsonReader({ totalProperty: "totalProperty", root: "root", fields: [{ name: "sID" }, { name: "cName"}] }) }); var pnProduct=new Ext.Panel({ id:'pnProduct', title:'商品信息', autoHeight:true, items:[ new Ext.Panel({ id:'pnProductRowOne', border:false, bodyStyle:'padding-top:10px;', layout:'column', items:[ new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'textfield', id:'ProductName', name:'ProductName', fieldLabel:'商品名称', anchor:'95%' } ] }), new Ext.Panel({ columnWidth:.25, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'radio', id:'DiscontinuedOneID', //hiddenName:'Discontinued', name:'Discontinued', inputValue:'1', fieldLabel:'是否停售', boxLabel:'是', anchor:'95%' } ] }), new Ext.Panel({ columnWidth:.25, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'radio', id:'DiscontinuedTwoID', //hiddenName:'Discontinued', name:'Discontinued', checked:true, inputValue:'0', boxLabel:'否', anchor:'95%' } ] }) ] }), new Ext.Panel({ id:'pnProductRowTwo', border:false, layout:'column', items:[ new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'textfield', id:'QuantityPerUnit', name:'QuantityPerUnit', fieldLabel:'规格', anchor:'95%' } ] }), new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'textfield', id:'UnitPrice', name:'UnitPrice', fieldLabel:'单价', anchor:'95%' } ] }) ] }), new Ext.Panel({ id:'pnProductRowThree', border:false, layout:'column', items:[ new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'textfield', id:'UnitsInStock', name:'UnitsInStock', fieldLabel:'库存量', anchor:'95%' } ] }) , new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'combo', id:'CommpanyName', //name:'CommpanyName', hiddenName:'SupplierID', fieldLabel:'供货商', displayField: 'cName', valueField: 'sID', mode: 'local', typeAhead: true, triggerAction: "all", editable: false, allowBlank: false, autoSelect: true, selectOnFoucus: true, store: stSupplier, anchor:'95%' } ] }) ] }) ] }); var pnCategory=new Ext.Panel({ id:'pnCategory', title:'商品相关种类信息', autoHeight:true, items:[ new Ext.Panel({ id:'pnCategoryRowOne', border:false, bodyStyle:'padding-top:10px;', layout:'column', items:[ new Ext.Panel({ columnWidth:.5, border:false, layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'textfield', id:'CategoryName', name:'CategoryName', fieldLabel:'商品种类', anchor:'95%' }, { xtype:'textfield', id:'Description', name:'Description', fieldLabel:'商品描述', anchor:'95%' }, { xtype:'hidden', id:'CategoryID', name:'CategoryID', fieldLabel:'种类编号'//这个是隐藏的 } ] }), new Ext.Panel({ columnWidth:.5, border:false, bodyStyle:'padding-left:25px;', layout:'form', labelWidth:60, labelAlign:'right', items:[ { xtype:'box',// id:'CategoryImage', width:172, height:120, autoEl:{ tag:'image', src:'tempFile/1.png' } } ] }) ] }) ] }); var tpProduct=new Ext.TabPanel({//很多时候我们可能是一个表单放在不同的tab中,为了方便提交和加载数据可以在tabpanel最外层放一个formpanel,但是显示就有问题,这个时候可以通过设置tabpanel高度和deferredRender、layoutOnTabChange两个属性来调整 id:'tpProduct', deferredRender:false,//是否第一次显示就渲染所有tab(默认为true) layoutOnTabChange:true, //height:300, //autoTabs:true, activeTab:0, border:false, items:[ pnProduct, pnCategory ] }); var fpProduct=new Ext.FormPanel({//作为TabPanel的容器 id:'fpProduct', reader: new Ext.data.JsonReader({ successProperty: 'success',//后台返回的json中成功与否的字段名称 root: 'info'//后台返回的json中,数据字段名称 }, [ 'ProductName', //'Discontinued', 'QuantityPerUnit', 'UnitPrice', 'UnitsInStock', 'CategoryID', 'CategoryName', 'Description', 'SupplierID' ] ), items:[ tpProduct ] }); var winProductInfo=new Ext.Window({ title:'商品信息', width:450, height:300, layout:'fit', closeAction:'hide', plain:true,//true则主体背景透明,false则和主体背景有些差别 collapsible:true,//是否可收缩 modal:true,//是否为模式窗体 items:[ fpProduct ], buttons:[//窗体按钮 { text:'提交', handler:function(){ if(fpProduct.getForm().isValid()){ var record=grdProduct.getSelectionModel().getSelected(); fpProduct.getForm().submit({ method:'post', url:'ProductInfo.aspx?type=updateProductInfo&productId='+record.get("ProductID"), waitMsg:'数据更新中...', success:function(){ stProduct.reload(); Ext.Msg.alert("系统提示","提交成功!"); }, failure:function(){ Ext.Msg.alert("系统提示","提交失败!"); } }); } } }, { text:'关闭', handler:function(){//点击时触发的事件 winProductInfo.hide(); } } ] }); // Ext.getCmp('tp').on("tabchange",function(tabPanel,tab){ // Ext.Msg.alert("系统提示","Tab标题:"+tab.title); // }); grdProduct.on("rowdblclick",function(grid,rowIndex,e){ var row=grid.getStore().getAt(rowIndex).data; //Ext.Msg.alert("系统提示","行:"+rowIndex+" 产品ID:"+row.ProductID); fpProduct.form.load({//利用load自动填充,注意表单控件字段一定要和json中一致 url:'ProductInfo.aspx?type=getProductInfo&productId='+row.ProductID, waitMsg:'数据加载中...', success:function(){ //alert("tempFile/"+row.CategoryName+".png"); if(row.Discontinued=="是"){ Ext.getCmp('DiscontinuedOneID').setValue(true); }else{ Ext.getCmp('DiscontinuedTwoID').setValue(true); } Ext.getCmp('CategoryImage').getEl().dom.src="tempFile/"+row.CategoryName+".png"; }, failure:function(){ Ext.Msg.alert("系统提示","数据加载失败!"); } }); winProductInfo.show(); }); var pnCenter=new Ext.Panel({ id:'pnCenter', region:'center', items:[ grdProduct ] }); var vp=new Ext.Viewport({ id:'vp', layout:'border', renderTo:Ext.getBody(), items:[ pnNorth, pnCenter ] }); }); // --></mce:script> <mce:style type="text/css"><!-- .btn_search { background: url(ext/resources/images/cmj/btn_search.png) left top no-repeat !important; } .btn_help { background: url(ext/resources/images/cmj/btn_help.png) left top no-repeat !important; } --></mce:style><style type="text/css" mce_bogus="1"> .btn_search { background: url(ext/resources/images/cmj/btn_search.png) left top no-repeat !important; } .btn_help { background: url(ext/resources/images/cmj/btn_help.png) left top no-repeat !important; } </style> </head> <body> </body> </html>

下面是后台代码(主要是FromPanel相关数据,不包括GridPanel数据的加载):

主要业务代码

using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Text; using Cmj.MyData; namespace GridPanel { public partial class ProductInfo : System.Web.UI.Page { DBHelper dbHelper = new DBHelper();//自定义数据库操作类 protected void Page_Load(object sender, EventArgs e) { string type = ""; string productId = ""; if (!string.IsNullOrEmpty(Request["type"])) { type = Request["type"]; } if (!string.IsNullOrEmpty(Request["productId"])) { productId = Request["productId"]; } if (type == "getProductInfo") { Response.Write(GetProductInfo(productId)); } else if (type == "getSupplierInfo") { Response.Write(GetSupplierInfo()); } //else if (type == "getCategoryInfo") //{ //} else if (type == "updateProductInfo") { string productName = Request["ProductName"].Replace("'","''"); string discontinued = Request["Discontinued"]; string QuantityPerUnit = Request["QuantityPerUnit"]; string UnitPrice = Request["UnitPrice"]; string UnitsInStock = Request["UnitsInStock"]; string SupplierID = Request["SupplierID"]; string CategoryID = Request["CategoryID"]; string CategoryName = Request["CategoryName"]; string Description = Request["Description"]; UpdateProductInfo(productId,productName,discontinued,QuantityPerUnit,UnitPrice,UnitsInStock,SupplierID,CategoryID,CategoryName,Description); Response.Write("{success:true}"); } Response.End(); } private string GetProductInfo(string productId) { try { string sql = "SELECT dbo.Products.ProductName,dbo.Products.QuantityPerUnit,dbo.Products.UnitPrice,dbo.Products.UnitsInStock,dbo.Products.Discontinued, " + "dbo.Categories.CategoryID,dbo.Categories.CategoryName,dbo.Categories.Description ,dbo.Products.SupplierID FROM dbo.Products INNER JOIN dbo.Categories ON dbo.Products.CategoryID = dbo.Categories.CategoryID WHERE dbo.Products.ProductID='" + productId + "'"; DataTable dt = dbHelper.GetDataTable(CommandType.Text, sql); StringBuilder sb = new StringBuilder("{success:true,info:["); sb.Append(GetJsonFromDataTable(dt)); sb.Append("]}"); return sb.ToString(); } catch (Exception ex) { return "{success:false}"; } } private string GetSupplierInfo() { try { string sql = "SELECT DISTINCT dbo.Suppliers.SupplierID as sID,dbo.Suppliers.CompanyName as cName FROM dbo.Suppliers"; DataTable dt = dbHelper.GetDataTable(CommandType.Text, sql); StringBuilder sb = new StringBuilder("{totalProperty:"); sb.Append(dt.Rows.Count); sb.Append(",root:["); sb.Append(GetJsonFromDataTable(dt)); sb.Append("]}"); return sb.ToString(); } catch (Exception ex) { return "{success:false}"; } } private void UpdateProductInfo(string productId,string productName,string discontinued,string QuantityPerUnit,string UnitPrice,string UnitsInStock,string SupplierID,string CategoryID,string CategoryName,string Description) { string sqlForUpdateProduct = "UPDATE dbo.Products SET ProductName='" + productName + "',Discontinued='" + discontinued + "',QuantityPerUnit='" + QuantityPerUnit + "'," + "SupplierID='" + SupplierID + "',UnitPrice='" + UnitPrice + "',UnitsInStock='" + UnitsInStock + "' WHERE ProductID='" + productId + "'"; string sqlForUpdateCategory = "UPDATE dbo.Categories SET CategoryName='" + CategoryName + "',Description='" + Description + "' WHERE CategoryID='" + CategoryID + "'"; dbHelper.ExcuteNonQuery(CommandType.Text, sqlForUpdateProduct); dbHelper.ExcuteNonQuery(CommandType.Text, sqlForUpdateCategory); } /// <summary> /// 辅助方法,将DataTalbe转化成json字符串 /// </summary> /// <param name="dataTable"></param> /// <returns></returns> private string GetJsonFromDataTable(DataTable dataTable) { bool r=false; StringBuilder json = new StringBuilder(); foreach (DataRow dr in dataTable.Rows) { json.Append("{"); foreach (DataColumn dc in dataTable.Columns) { if (bool.TryParse(dr[dc.ColumnName].ToString(), out r))//如果是bool型,则json值不加双引号 { json.AppendFormat("{0}:{1},", dc.ColumnName, dr[dc.ColumnName].ToString().ToLower()); } else { json.AppendFormat("{0}:/"{1}/",", dc.ColumnName, dr[dc.ColumnName]); } } json.Remove(json.ToString().Length - 1, 1); json.Append("},"); } json.Remove(json.ToString().Length - 1, 1); //json.Append("}"); return json.ToString(); } } }

实体辅助类

using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; namespace GridPanel { public class Product { public string ProductID { get; set; } public string ProductName { get; set; } public string CategoryName { get; set; } public double UnitPrice { get; set; } public string Discontinued { get; set; } public string QuantityPerUnit { get; set; } public string CompanyName { get; set; } } }

简单的看一下效果:

当我们双击GridPanel某行时将弹出对应商品的相关信息(在window控件中显示),我们可以修改其中的信息进行提交。而且在这个例子中我们会向大家展示了如何在FormPanel中嵌套TabPanel。我们知道有很多时候我们的信息通过一个窗口无法完全显示,此时有些朋友会选择在TabPanel中使用FromPanel,但是这样一来造成的问题就是每个Tab中的FromPanel在提交时都是独立的,如果想要同时提交就比较麻烦了(当然你可以选择使用Ext.Ajax.request通过手动获得每个字段的值来提交,但是却很麻烦)。因此,这里我们选择使用FromPanel嵌套TabPanel的方式(由于例子受Northwind业务限制,因此较难找到合适的多Tab同时提交的例子。这里为了给大家展示多个Tab同时提交,就有意的将商品信息的修改和种类的修改组合到一块修改提交,在业务上可能有所不当,故在此声明!)。

注意

代码不是太复杂,但是还是要提醒大家注意一下几点:

  1. 关于TabPanel放在FromPanel中时注意deferredRender、layoutOnTabChange属性的使用(由于其中有很多panel一定注意不要把id弄重复了)。
  2. 使用FormPanel的加载方法(load)来自动加载时一定要注意FromPanel的reader属性的定义(特别是其中的字段一定要和From控件一致),这一点做不好很容易load失败。
  3. 在使用FromPanel的Load方法时注意comboBox、radio(name相同后台返回一个值)、checkbox(name值不同,所以后台返回多个值,返回值必须是true或false)等的赋值。comboBox和radio(虽然例子中没有出现,但是经过测试只要嵌套正常布局[注意同一组radio,name不同],后台返回时只返回需要勾选的键值对[在json中]就可以了)都可以通过load自动加载,可是checkBox确没有找到合适的方法,最终通过在load成功是判读来手动赋值,知道的朋友麻烦说一下。
  4. 例子中还用到了显示图片功能,此方法也是开发中常用的方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值