GridView自定义用户控件实现增、删、改

以下是我的用户控件代码,暂时定义为MyGridView,当然它继承于GridView。

public partial class MyGridView : GridView
    {
        public MyGridView()
        {
            ViewState["SHOWBUFFER"] = new DataTable();
            ViewState["DATABUFFER"] = new DataTable();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            
        }

        #region 属性

        private string[] _LIST_REQCOLUMN;
        /// <summary>
        /// 非空列列表
        /// </summary>
        [Description("非空列列表,注意:列名必须是DataPropertyName")]
        public string[] LIST_REQCOLUMN
        {
            get { return _LIST_REQCOLUMN; }
            set { _LIST_REQCOLUMN = value; }
        }

        private string _SORTCOLUMN = "";
        /// <summary>
        /// 排序字段名称
        /// </summary>
        [Description("排序字段名称,此处注册后,行移动将改变此字段值")]
        public string SORTCOLUMN
        {
            get { return _SORTCOLUMN; }
            set { _SORTCOLUMN = value; }
        }

        private bool _IS_SAVE_SORT;
        public bool IS_SAVE_SORT
        {
            get { return _IS_SAVE_SORT; }
            set { _IS_SAVE_SORT = value; }
        }

        #endregion

        #region 公用方法
        /// <summary>获取ROWID
        /// 获取ROWID
        /// </summary>
        /// <returns>最新的ROWID</returns>
        public int GetRowid()
        {
            int ROWID = 0;

            if (ViewState["ROWID"] == null)
            {
                ROWID = 1;
                ViewState["ROWID"] = 1;
            }
            else
            {
                ROWID = (int)ViewState["ROWID"];
                ROWID = ROWID + 1;
                ViewState["ROWID"] = ROWID;
            }

            return ROWID;
        }

        /// <summary>
        /// DataTable的行拷贝,参数aDR:要复制的行,返回复制完成的行
        /// </summary>
        /// <param name="aDR">要被复制的DataTable行</param>
        /// <returns>已经复制好的行</returns>
        [Description("DataTable的行拷贝,参数aDR:要复制的行,返回复制完成的行")]
        protected DataRow RowCopy(DataRow aDR)
        {

            DataRow retDr = aDR.Table.NewRow();
            retDr.ItemArray = aDR.ItemArray;

            return retDr;
        }

        /// <summary>
        /// DataTable的行拷贝,参数aDT:要复制的DataTable,aRowNum:要复制行的行号,返回复制完成的行
        /// </summary>
        /// <param name="aDT">要操作的DataTable</param>
        /// <param name="aRowNum">要复制行的行号</param>
        /// <returns>返回复制完成的行</returns>
        [Description("DataTable的行拷贝,参数aDT:要复制的DataTable,aRowNum:要复制行的行号,返回复制完成的行")]
        protected DataRow RowCopy(DataTable aDT, int aRowNum)
        {
            return RowCopy(aDT.Rows[aRowNum]);
        }

        /// <summary>
        /// 查找指定列名的列是否存在
        /// </summary>
        /// <param name="aColumnName">列名</param>
        /// <returns>如果列存在则返回列号,否则返回-1</returns>
        [Description("查找指定列名的列是否存在,如果列存在则返回列号,否则返回-1")]
        public int FindColumn(DataTable aDt, string aColumnName)
        {
            int vColIndex = -1;
            for (int i = 0; i < aDt.Columns.Count; i++)
            {
                if (aDt.Columns[i].ColumnName.ToUpper() == aColumnName.ToUpper())
                {
                    vColIndex = i;
                    break;
                }
            }

            return vColIndex;
        }

        /// <summary>
        /// 获取指定列号列的名称
        /// </summary>
        /// <param name="aColumnIndex">列号</param>
        /// <returns>找到列的名称,如果列号小于0或大于等于列总数则返回“”</returns>
        [Description("获取指定列号列的名称,如果列号小于0或大于等于列总数则返回“”")]
        public string FindColumn(int aColumnIndex)
        {
            string vColunnName = "";
            DataTable DT = GetShowBufferData();
            if (aColumnIndex < 0 || aColumnIndex >= DT.Columns.Count)
            {
                vColunnName = "";
            }
            else
            {
                vColunnName = DT.Columns[aColumnIndex].ColumnName;
            }

            return vColunnName;
        }

        public string GetColumnHeadText(int aColumnIndex)
        {
            string vHeaderText = "";
            if(!(aColumnIndex < 0 || aColumnIndex >= Columns.Count))
            {
                vHeaderText = (Columns[aColumnIndex].HeaderText);
            }

            return vHeaderText;
        }
        #endregion

        #region 数据操作相关方法

        /// <summary>
        /// 得到需要保存的(新增、修改、删除)记录列表
        /// </summary>
        /// <returns>需要保存的记录列表</returns>
        [Description("得到需要保存的(新增、修改、删除)记录列表")]
        public virtual DataTable GetSaveRow()
        {
            string FilterStr = "";
            DataTable DATABUFFER = (DataTable) ViewState["DATABUFFER"];
            DataTable SHOWBUFFER = (DataTable)ViewState["SHOWBUFFER"];
            DataTable saveTable = DATABUFFER.Clone();
            int colnum = saveTable.Columns.Count;
            for (int i = 0; i < colnum; i++)
            {
                DataColumn dcol = saveTable.Columns[i];
                saveTable.Columns.Add(dcol.ColumnName + "_OLD", dcol.DataType);
            }
            saveTable.Columns.Add("OPTYPE", Type.GetType("System.String"));

            #region 收集修改过的和新增记录
            foreach (DataRow drFind in SHOWBUFFER.Rows)
            {
                FilterStr = "ROWID = " + drFind["ROWID"].ToString();

                DataRow[] foundRows = DATABUFFER.Select(FilterStr);
                if (foundRows.Length > 0)
                {//收集修改记录列表
                    bool isEqual = true;
                    for (int i = 0; i < SHOWBUFFER.Columns.Count; i++)
                    {
                        string vCol = SHOWBUFFER.Columns[i].ColumnName;
                        //if (!drFind[vCol].ToString.Equals(foundRows[0][vCol]))
                        if (drFind[vCol].ToString() != foundRows[0][vCol].ToString())
                        {
                            isEqual = false;
                            break;
                        }
                    }

                    if (!isEqual)
                    {
                        DataRow drSave = saveTable.NewRow();
                        int colscnt = drFind.ItemArray.Length;
                        for (int i = 0; i < colscnt; i++)
                        {
                            drSave[SHOWBUFFER.Columns[i].ColumnName] = drFind[SHOWBUFFER.Columns[i].ColumnName];
                            if (SHOWBUFFER.Columns[i].ColumnName.ToUpper() != "ROWID")
                            {
                                drSave[SHOWBUFFER.Columns[i].ColumnName + "_OLD"] = foundRows[0][SHOWBUFFER.Columns[i].ColumnName];
                            }
                        }
                        
                        drSave["OPTYPE"] = "UPDATE";
                        saveTable.Rows.Add(drSave);
                    }
                }
                else
                {
                    DataRow drSave = saveTable.NewRow();
                    int colscnt = drFind.ItemArray.Length;
                    for (int i = 0; i < colscnt; i++)
                    {
                        drSave[SHOWBUFFER.Columns[i].ColumnName] = drFind[SHOWBUFFER.Columns[i].ColumnName];
                    }

                    drSave["OPTYPE"] = "INSERT";
                    saveTable.Rows.Add(drSave);
                }
            }
            #endregion

            #region 收集被删除的记录
            foreach (DataRow fdr in DATABUFFER.Rows)
            {
                FilterStr = "ROWID = " + fdr["ROWID"].ToString();

                DataRow[] foundRow = SHOWBUFFER.Select(FilterStr);
                if (foundRow.Length < 1)
                {
                    DataRow drSave = saveTable.NewRow();
                    int colscnt = fdr.ItemArray.Length;
                    for (int i = 0; i < colscnt; i++)
                    {
                        drSave[i] = fdr[i];
                    }

                    drSave["OPTYPE"] = "DELETE";
                    saveTable.Rows.Add(drSave);
                }
            }
            #endregion

            return saveTable;
        }

        /// <summary>
        /// 数据查询
        /// </summary>
        /// <param name="dt">要绑定的数据</param>
        [Description("数据查询,需要DataTable")]
        public void SetData(DataTable dt)
        {
            int colrowid = FindColumn(dt,"ROWID");
            if (colrowid == -1)
            {
                dt.Columns.Add("ROWID", Type.GetType("System.Int32"));
            }
            

            foreach (DataRow dr in dt.Rows)
            {
                dr["ROWID"] = GetRowid();
            }

            DataTable DATABUFFER = dt.Copy();
            DataTable SHOWBUFFER = dt;
            DataSource = SHOWBUFFER;
            DataBind();

            SetShowBufferData(SHOWBUFFER);
            SetDataBufferData(DATABUFFER);
        }

        /// <summary>
        /// 获取显示缓冲数据
        /// </summary>
        /// <returns></returns>
        [Description("获取显示缓冲数据,返回DataTable")]
        public DataTable GetShowBufferData()
        {
            if (ViewState["SHOWBUFFER"] == null) ViewState["SHOWBUFFER"] = new DataTable();
            return (DataTable)ViewState["SHOWBUFFER"];
        }

        /// <summary>
        /// 获取原始缓冲数据
        /// </summary>
        /// <returns></returns>
        [Description("获取原始缓冲数据,返回DataTable")]
        public DataTable GetDataBufferData()
        {
            if (ViewState["DATABUFFER"] == null) ViewState["DATABUFFER"] = new DataTable();
            return (DataTable)ViewState["DATABUFFER"];
        }

        /// <summary>
        /// 缓冲显示数据
        /// </summary>
        /// <param name="aDt">要缓冲的数据</param>
        [Description("缓冲显示数据")]
        public void SetShowBufferData(DataTable aDt)
        {
            ViewState["SHOWBUFFER"] = aDt;
        }

        /// <summary>
        /// 缓冲原始数据
        /// </summary>
        /// <param name="aDt">要缓冲的数据</param>
        [Description("缓冲原始数据")]
        public void SetDataBufferData(DataTable aDt)
        {
            ViewState["DATABUFFER"] = aDt;
        }

        /// <summary>
        /// 数据非空检查
        /// </summary>
        /// <returns>true:通过检查,false:未通过检查</returns>
        [Description("数据非空检查,返回true:通过检查,false:未通过检查")]
        public string DataNotNullCheck()
        {
            DataTable SHOWBUFFER = (DataTable)ViewState["SHOWBUFFER"];
            bool vMark = true;
            string vRet = "";
            if (LIST_REQCOLUMN.Length > 0)
            {
                for (int vRow = 0; vRow < Rows.Count; vRow++)
                {
                    for (int vCol = 0; vCol < LIST_REQCOLUMN.Length; vCol++)
                    {
                        if (SHOWBUFFER.Rows[vRow][LIST_REQCOLUMN[vCol]] == DBNull.Value)
                        {
                            vMark = false;
                            vRet = "第" + vRow.ToString() + "行,第" + vCol.ToString() + "列不能为空!";

                            break;
                        }
                    }

                    if (!vMark) break;
                }
            }

            return vRet;
        }

        /// <summary>
        /// 新增一行
        /// </summary>
        /// <returns>返回GridView新增的行</returns>
        public GridViewRow AddRow()
        {
            DataTable showBuffer = GetShowBufferData();
            DataRow newRow = showBuffer.NewRow();
            int vRowId = GetRowid();
            newRow["ROWID"] = vRowId;
            showBuffer.Rows.Add(newRow);

            DataSource = showBuffer;
            DataBind();
            SetShowBufferData(showBuffer);

            return Rows[Rows.Count - 1];
        }

        /// <summary>
        /// 删除指定行号的记录
        /// </summary>
        /// <param name="aRowIndex">要删除行的行号</param>
        public void DeleteRow(List<int> aRowIndex)
        {
            if (aRowIndex.Count < 1) return;

            int vMark = 0;
            for (int i = 0; i < aRowIndex.Count; i++)
            {
                vMark = aRowIndex[i];
                for (int j = i + 1; j < aRowIndex.Count; j++)
                {
                    if (vMark > aRowIndex[j])
                    {
                        vMark = aRowIndex[j];
                    }
                }
                aRowIndex[i] = vMark;
            }

            DataTable showBuffer = GetShowBufferData();
            for (int i = aRowIndex.Count - 1; i >= 0; i--)
            {
                showBuffer.Rows.RemoveAt(aRowIndex[i]);
            }

            DataSource = showBuffer;
            DataBind();
            SetShowBufferData(showBuffer);
        }
        #endregion
    }

上面的MyGridView已经完成了封装,在页面中拖入该用户控件即可,后台中就可以调用相关的方法。下面看看在页面中怎么实现增、删、改


查询

在页面初始化时,调用封装类中的SetData方法


插入 之前

//同步展示表数据
        public void SendGridViewToShowBUffer()
        {
            DataTable showbuffer = gvAccount.GetShowBufferData();

            foreach (GridViewRow gvrow in gvAccount.Rows)
            {
                int RowIndex = gvrow.RowIndex;

                Label lblID = (Label)gvrow.FindControl("lblID");
                showbuffer.Rows[RowIndex]["ID"] = lblID.Text == "" ? 0 : Convert.ToInt32(lblID.Text);

                DropDownList ddlItemSection = (DropDownList)gvrow.FindControl("ddlItemSection");
                showbuffer.Rows[RowIndex]["SECTION"] = ddlItemSection.SelectedValue;

                DropDownList ddlItemSubject = (DropDownList)gvrow.FindControl("ddlItemSubject");
                showbuffer.Rows[RowIndex]["SUBJECT"] = ddlItemSubject.SelectedValue == "" ? 0 : Convert.ToInt32(ddlItemSubject.SelectedValue);

                TextBox txtAmount = (TextBox)gvrow.FindControl("txtAmount");
                showbuffer.Rows[RowIndex]["AMOUNT"] = txtAmount.Text == "" ? 0.00M : Convert.ToDecimal(txtAmount.Text);

                TextBox txtOccuredTime = (TextBox)gvrow.FindControl("txtOccuredTime");
                showbuffer.Rows[RowIndex]["OCCURED_TIME"] = txtOccuredTime.Text.ToString();

                DropDownList ddlItemCreator = (DropDownList)gvrow.FindControl("ddlItemCreator");
                showbuffer.Rows[RowIndex]["CREATOR"] = ddlItemCreator.SelectedValue;

                TextBox txtCreatedTime = (TextBox)gvrow.FindControl("txtCreatedTime");
                showbuffer.Rows[RowIndex]["CREATED_TIME"] = txtCreatedTime.Text.ToString();

                DropDownList ddlCommitFlag = (DropDownList)gvrow.FindControl("ddlCommitFlag");
                showbuffer.Rows[RowIndex]["COMMIT_FLAG"] = ddlCommitFlag.SelectedValue;

                DropDownList ddlItemProject = (DropDownList)gvrow.FindControl("ddlItemProject");
                try
                {
                    showbuffer.Rows[RowIndex]["PROJECT"] = Convert.ToInt32(ddlItemProject.SelectedValue);
                }
                catch
                {
                    showbuffer.Rows[RowIndex]["PROJECT"] = DBNull.Value;
                }

                TextBox txtRemark = (TextBox)gvrow.FindControl("txtRemark");
                showbuffer.Rows[RowIndex]["REMARK"] = txtRemark.Text;
            }

            gvAccount.SetShowBufferData(showbuffer);
        }

这个方法很重要,无论执行增、删还是改都得调用该方法,GridViewRow中的列根据自己的需要修改。


插入

 protected void btnAdd_Click(object sender, EventArgs e)
        {
            SendGridViewToShowBUffer();
            GridViewRow gr = gvAccount.AddRow();

            DropDownList ddlItemCreator = (DropDownList)gr.FindControl("ddlItemCreator");
            ddlItemCreator.SelectedValue = GetUser();

            TextBox txtCreatedTime = (TextBox)gr.FindControl("txtCreatedTime");
            txtCreatedTime.Text = DateTime.Now.ToString("yyyy-MM-dd");
        }


删除

protected void btnDelete_Click(object sender, EventArgs e)
        {
            SendGridViewToShowBUffer();
            int cnt = gvAccount.Rows.Count;
            List<int> vDelRowList = new List<int>();
            for (int i = 0; i < cnt; i++)
            {
                GridViewRow gvr = gvAccount.Rows[i];
                CheckBox cbs = (CheckBox)gvr.FindControl("ckbSelect");
                if (cbs.Checked)
                {
                    vDelRowList.Add(i);
                }
            }

            gvAccount.DeleteRow(vDelRowList);
        }


保存

 public string SaveAccount()
        {
            string vRet = string.Empty;
            bool vFlag = ValCell();
            if (vFlag == true)
            {
                SendGridViewToShowBUffer();
                DataTable saveData = gvAccount.GetSaveRow();
                List<T_SECTION_INOUT> vProjectList = new List<T_SECTION_INOUT>();
                for (int i = 0; i < saveData.Rows.Count; i++)
                {
                    DataRow dr = saveData.Rows[i];
                    T_SECTION_INOUT vAccount = new T_SECTION_INOUT();
                    string vOpType = dr["OPTYPE"].ToString();
                    vAccount.OPTYPE = vOpType;

                    switch (vOpType)
                    {
                        case "DELETE":
                            {
                                vAccount.ID = Convert.ToInt32(dr["ID"].ToString());
                                break;
                            }
                        case "INSERT":
                            {
                                vAccount.Section = dr["SECTION"].ToString();
                                vAccount.Subject = dr["SUBJECT"].ToString();
                                vAccount.Amount = Convert.ToDecimal(dr["AMOUNT"].ToString());
                                vAccount.OccuredTime = Convert.ToDateTime(dr["OCCURED_TIME"].ToString());
                                vAccount.Creator = dr["CREATOR"].ToString(); ;
                                vAccount.CreatedTime = Convert.ToDateTime(dr["CREATED_TIME"].ToString());
                                vAccount.CommitFlag = Convert.ToChar(dr["COMMIT_FLAG"].ToString());
                                vAccount.Project = Convert.ToInt32(dr["PROJECT"].ToString());
                                vAccount.Remark = dr["REMARK"].ToString();
                                break;
                            }
                        case "UPDATE":
                            {
                                vAccount.ID = Convert.ToInt32(dr["ID"].ToString());
                                vAccount.Section = dr["SECTION"].ToString();
                                vAccount.Subject = dr["SUBJECT"].ToString();
                                vAccount.Amount = Convert.ToDecimal(dr["AMOUNT"].ToString());
                                vAccount.OccuredTime = Convert.ToDateTime(dr["OCCURED_TIME"].ToString());
                                vAccount.Creator = dr["CREATOR"].ToString(); ;
                                vAccount.CreatedTime = Convert.ToDateTime(dr["CREATED_TIME"].ToString());
                                vAccount.CommitFlag = Convert.ToChar(dr["COMMIT_FLAG"].ToString());
                                vAccount.Project = Convert.ToInt32(dr["PROJECT"].ToString());
                                vAccount.Remark = dr["REMARK"].ToString();
                                break;
                            }
                        default:
                            break;
                    }

                    vProjectList.Add(vAccount);
                }

                vRet = useBusiness.SaveAccount(vProjectList);

                return vRet;
            }
            else
            {
                return "数据验证不通过!";
            }
        }

//保存
        protected void btnSave_Click(object sender, EventArgs e)
        {
            string vSaveMsg = SaveAccount();
            BindAccountData();
            if (string.IsNullOrEmpty(vSaveMsg))
            {
                Response.Write("<script>alert('保存成功!');</script>");
            }
        }


保存调用的业务逻辑代码

public string SaveAccount(List<T_SECTION_INOUT> objList)
        {
            string ret = "";
            string sql = "";
            List<DbParameter> iParms = new List<DbParameter>();

            for (int i = 0; i < objList.Count; i++)
            {
                switch (objList[i].OPTYPE.ToUpper())
                {
                    case "INSERT":
                        {
                            sql += @" insert into T_SECTION_INOUT
                                          (SECTION,
                                           SUBJECT,
                                           AMOUNT,
                                           OCCURED_TIME,
                                           CREATOR,
                                           CREATED_TIME,
                                           COMMIT_FLAG,
                                           PROJECT,
                                           REMARK)
                                        values
                                       (@SECTION" + i.ToString() + ",@SUBJECT" + i.ToString() + ",@AMOUNT" + i.ToString() + ",";
                            sql += "   @OCCURED_TIME" + i.ToString() + ",@CREATOR" + i.ToString() + ",@CREATED_TIME" + i.ToString() + ",@COMMIT_FLAG" + i.ToString() + ",@PROJECT" + i.ToString() + ",";
                            sql += "   @REMARK" + i.ToString() + ");";
                            iParms.Add(new SqlParameter("@SECTION" + i.ToString(), objList[i].Section));
                            iParms.Add(new SqlParameter("@SUBJECT" + i.ToString(), objList[i].Subject));
                            iParms.Add(new SqlParameter("@AMOUNT" + i.ToString(), objList[i].Amount));
                            iParms.Add(new SqlParameter("@OCCURED_TIME" + i.ToString(), objList[i].OccuredTime));
                            iParms.Add(new SqlParameter("@CREATOR" + i.ToString(), objList[i].Creator));
                            iParms.Add(new SqlParameter("@CREATED_TIME" + i.ToString(), objList[i].CreatedTime));
                            iParms.Add(new SqlParameter("@COMMIT_FLAG" + i.ToString(), objList[i].CommitFlag));
                            iParms.Add(new SqlParameter("@PROJECT" + i.ToString(), objList[i].Project));
                            iParms.Add(new SqlParameter("@REMARK" + i.ToString(), objList[i].Remark));
                            break;
                        }
                    case "UPDATE":
                        {
                            sql += @" update T_SECTION_INOUT set SECTION = @SECTION" + i.ToString() + ", SUBJECT = @SUBJECT" + i.ToString();
                            sql += " ,AMOUNT = @AMOUNT" + i.ToString() + ", OCCURED_TIME = @OCCURED_TIME" + i.ToString() + ", CREATOR = @CREATOR" + i.ToString() + ", CREATED_TIME = @CREATED_TIME" + i.ToString();
                            sql += " ,COMMIT_FLAG = @COMMIT_FLAG" + i.ToString();
                            sql += " ,PROJECT = @PROJECT" + i.ToString();
                            sql += " ,REMARK = @REMARK" + i.ToString();
                            sql += " where ID = @ID" + i.ToString() + ";";
                            iParms.Add(new SqlParameter("@ID" + i.ToString(), objList[i].ID));
                            iParms.Add(new SqlParameter("@SECTION" + i.ToString(), objList[i].Section));
                            iParms.Add(new SqlParameter("@SUBJECT" + i.ToString(), objList[i].Subject));
                            iParms.Add(new SqlParameter("@AMOUNT" + i.ToString(), objList[i].Amount));
                            iParms.Add(new SqlParameter("@OCCURED_TIME" + i.ToString(), objList[i].OccuredTime));
                            iParms.Add(new SqlParameter("@CREATOR" + i.ToString(), objList[i].Creator));
                            iParms.Add(new SqlParameter("@CREATED_TIME" + i.ToString(), objList[i].CreatedTime));
                            iParms.Add(new SqlParameter("@COMMIT_FLAG" + i.ToString(), objList[i].CommitFlag));
                            iParms.Add(new SqlParameter("@PROJECT" + i.ToString(), objList[i].Project));
                            iParms.Add(new SqlParameter("@REMARK" + i.ToString(), objList[i].Remark));
                            break;
                        }
                    case "DELETE":
                        {
                            sql += @"delete T_SECTION_INOUT where ID = @ID" + i.ToString() + ";";
                            iParms.Add(new SqlParameter("@ID" + i.ToString(), objList[i].ID));
                            break;
                        }
                    default:
                        break;
                }
            }

            try
            {
                Excute(sql, iParms);
            }
            catch (Exception ex)
            {
                ret = ex.Message;
            }

            return ret;
        }


整体上就是这么多,如果想熟练使用该控件,还需要把MyGridView类库中的方法给搞清楚。写这篇文章的主要目的还是想分享这个类库,后面的增、删、改只是针对自己项目进行的简单运用,欢迎各位交流,时间不早了,哎呀、今天终于睡迟了一回,各位晚安!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值