经典三层架构(界面层为Developer Express第三方控件)

今天就说一下经典的三层架构,所以就已一个简单的例子来讲,下面就切入正题。

  1. 建立数据库Test,按照下面的脚本即可建立这个简单的数据结构了,简单吧…

  

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
if exists ( select * from sysobjects where id = OBJECT_ID ( ' [Parent] ' ) and OBJECTPROPERTY (id, ' IsUserTable ' ) = 1 )
DROP TABLE [ Parent ]

CREATE TABLE [ Parent ] (
[ ID ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ ParentCode ] [ nvarchar ] ( 50 ) NULL ,
[ ParentName ] [ nvarchar ] ( 50 ) NULL )

ALTER TABLE [ Parent ] WITH NOCHECK ADD CONSTRAINT [ PK_Parent ] PRIMARY KEY NONCLUSTERED ( [ ID ] )
SET IDENTITY_INSERT [ Parent ] ON

SET IDENTITY_INSERT [ Parent ] OFF
if exists ( select * from sysobjects where id = OBJECT_ID ( ' [Son] ' ) and OBJECTPROPERTY (id, ' IsUserTable ' ) = 1 )
DROP TABLE [ Son ]

CREATE TABLE [ Son ] (
[ ID ] [ int ] IDENTITY ( 1 , 1 ) NOT NULL ,
[ ParentID ] [ int ] NULL ,
[ SonCode ] [ nvarchar ] ( 50 ) NULL ,
[ SonName ] [ nvarchar ] ( 50 ) NULL )

ALTER TABLE [ Son ] WITH NOCHECK ADD CONSTRAINT [ PK_Son ] PRIMARY KEY NONCLUSTERED ( [ ID ] )
SET IDENTITY_INSERT [ Son ] ON

SET IDENTITY_INSERT [ Son ] OFF

这样数据库就建好了,接下来就是建立解决方案了。

 

  1. 打开VS2008(VS系列,随便你是200几了,都一样),新建一个空解决方案,然后解决方案里,然后在这个解决方案下面新建3个类库项目和一个Windows窗体控件库(方便调试,你也可以新建Windows窗体应用程序),解决方案结构如下:

  2010080112264440.jpg

好了,这时候就可以开始我们的三层架构编程了,首先是Model层,这个Model对应的数据库里的每一个数据表,这里就是Panent和Son了,所以Model层里面就有2个点cs文件,文件内容如下:

 

Parent.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Parent表的实体类
* 主要功能:Parent表的实体类
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Model
{
/// <summary>
/// Parent表的实体类
/// </summary>
public class Parent
{
#region 构造器
/// <summary>
/// 默认构造器
/// </summary>
public Parent()
{ }
#endregion

#region Model
private int _id;
private string _parentcode;
private string _parentname;
/// <summary>
/// ID
/// </summary>
public int ID
{
set { _id = value;}
get { return _id;}
}
/// <summary>
/// 主表编码
/// </summary>
public string ParentCode
{
set { _parentcode = value;}
get { return _parentcode;}
}
/// <summary>
/// 主表名称
/// </summary>
public string ParentName
{
set { _parentname = value;}
get { return _parentname;}
}
#endregion Model

private List < Son > _sons;
/// <summary>
/// 子类
/// </summary>
public List < Son > Sons
{
set { _sons = value;}
get
{
if (_sons == null )
{
_sons
= new List < Son > ();
return _sons;
}
else
{
return _sons;
}
}
}
}
}

 

Son.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Son表的实体类
* 主要功能:Son表的实体类
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Model
{
/// <summary>
/// Son表的实体类
/// </summary>
public class Son
{
#region 构造器
/// <summary>
/// 默认构造器
/// </summary>
public Son()
{ }
#endregion

#region Model
private int _id;
private int ? _parentid;
private string _soncode;
private string _sonname;
/// <summary>
/// ID
/// </summary>
public int ID
{
set { _id = value; }
get { return _id; }
}
/// <summary>
/// 主表ID
/// </summary>
public int ? ParentID
{
set { _parentid = value; }
get { return _parentid; }
}
/// <summary>
/// 子表编码
/// </summary>
public string SonCode
{
set { _soncode = value; }
get { return _soncode; }
}
/// <summary>
/// 子表名称
/// </summary>
public string SonName
{
set { _sonname = value; }
get { return _sonname; }
}
#endregion Model
}
}

 

好了,Model层就完成了,Model层里面唯一需要注意的就是主子表的关系,所以这里面在Parent.cs里面就有一个子表的List。

 

在来就是DAL层了,这是数据访问层,数据访问层就是和数据库打交道的最底层,这里面的就是SQL语句了,这里也直接上代码了,也就是C(增)、R(查)、U(更新)和D(删)这样了。

ParentManager.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Parent表的数据访问层
* 主要功能:Parent表的数据访问层
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;
using System.Data.SqlClient;
using DevSpace.insight.DataAccessHelper;
using System.Data;

namespace DAL
{
/// <summary>
/// Parent表的数据访问层
/// </summary>
public class ParentManager
{
#region 新增数据
/// <summary>
/// 新增一条记录到Parent表
/// </summary>
/// <param name="parent"> Parent对象 </param>
/// <returns> 主键标识 </returns>
public static int Create(Parent parent)
{
try
{
int id = 0 ;
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ParentCode " , DAHelper.ReadParam(parent.ParentCode)));
paras.Add(
new SqlParameter( " @ParentName " , DAHelper.ReadParam(parent.ParentName)));

Object tempObj
= DAHelper.ExecuteScalar(
" INSERT INTO [dbo].[Parent](ParentCode, ParentName) " +
" VALUES(@ParentCode, @ParentName);SELECT @@IDENTITY " , CommandType.Text, paras);
id
= Convert.ToInt32(tempObj);
return id;
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}
#endregion

#region 查询数据
/// <summary>
/// 查询全部Parent表数据
/// </summary>
/// <returns> Parent全部结果集 </returns>
public static DataSet Read()
{
try
{
return DAHelper.ExecuteDataset( " SELECT * FROM [dbo].[Parent] " );
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}

/// <summary>
/// 查询全部Parent表数据
/// </summary>
/// <typeparam name="T"> Parent对象 </typeparam>
/// <returns> Parent全部结果集 </returns>
public static IList < Parent > GetModels()
{
string strQuery = " SELECT * FROM [dbo].[Parent] " ;
SqlDataReader reader
= DAHelper.ExecuteReader(strQuery);
return Common.GetModels < Parent > (reader);
}
/// <summary>
/// 查询主键ID为id的Parent表记录
/// </summary>
/// <typeparam name="T"> Parent对象 </typeparam>
/// <param name="id"> Parent表主键ID </param>
/// <returns> 主键ID为id的Parent表记录 </returns>
public static Parent ReadList( int id)
{
SqlParameter[] paras
= new SqlParameter[ 1 ];
paras[
0 ] = new SqlParameter( " @ID " , DAHelper.ReadParam(id));
string strQuery = " SELECT * FROM [dbo].[Parent] WHERE ID=@ID " ;
SqlDataReader reader
= DAHelper.ExecuteReader(strQuery, CommandType.Text, paras);
return Common.GetModels < Parent > (reader)[ 0 ];
}
#endregion

#region 更新数据

/// <summary>
/// 更新一条记录到Parent表
/// </summary>
/// <param name="parent"> Parent对象 </param>
/// <returns> 更新所影响的行数 </returns>
public static int Update(Parent parent)
{
try
{
int returnNum = 0 ;
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ID " , DAHelper.ReadParam(parent.ID)));
paras.Add(
new SqlParameter( " @ParentCode " , DAHelper.ReadParam(parent.ParentCode)));
paras.Add(
new SqlParameter( " @ParentName " , DAHelper.ReadParam(parent.ParentName)));

returnNum
= DAHelper.ExecuteNonQuery(
" UPDATE [dbo].[Parent] SET [ParentCode]=@ParentCode, [ParentName]=@ParentName " +
" WHERE [ID]=@ID " , CommandType.Text, paras);
return returnNum;
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}

#endregion

#region 删除数据

/// <summary>
/// 删除Parent表数据
/// </summary>
/// <param name="id"> Parent表主键ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int Delete( int id)
{
try
{
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ID " , DAHelper.ReadParam(id)));
return DAHelper.ExecuteNonQuery( " DELETE FROM [dbo].[Parent] WHERE ID=@ID " , CommandType.Text, paras);
}
catch (SqlException ex)
{
throw new Exception( " 删除失败,请与管理员联系! " + ex);
}
}

#endregion
}
}

 

SonManager.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Son表的数据访问层
* 主要功能:Son表的数据访问层
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Model;
using System.Data;
using DevSpace.insight.DataAccessHelper;
using System.Collections;

namespace DAL
{
/// <summary>
/// Son表的数据访问层
/// </summary>
public class SonManager
{
#region 新增数据
/// <summary>
/// 新增一条记录到Son表
/// </summary>
/// <param name="son"> Son对象 </param>
/// <returns> 主键标识 </returns>
public static int Create(Son son)
{
try
{
int id = 0 ;
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ParentID " , DAHelper.ReadParam(son.ParentID)));
paras.Add(
new SqlParameter( " @SonCode " , DAHelper.ReadParam(son.SonCode)));
paras.Add(
new SqlParameter( " @SonName " , DAHelper.ReadParam(son.SonName)));

Object tempObj
= DAHelper.ExecuteScalar(
" INSERT INTO [dbo].[Son](ParentID,SonCode, SonName) " +
" VALUES(@ParentID, @SonCode,@SonName);SELECT @@IDENTITY " , CommandType.Text, paras);
id
= Convert.ToInt32(tempObj);
return id;
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}
#endregion

#region 查询数据
/// <summary>
/// 查询全部Son表数据
/// </summary>
/// <returns> Son全部结果集 </returns>
public static DataSet Read()
{
try
{
return DAHelper.ExecuteDataset( " SELECT * FROM [dbo].[Son] " );
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}

/// <summary>
/// 查询主表ID为parentID的子表集合
/// </summary>
/// <typeparam name="T"> Son对象 </typeparam>
/// <param name="parentID"> 主表主键ID </param>
/// <returns> 主表ID为parentID的子表集合 </returns>
public static IList < Son > GetModels( int parentID)
{
SqlParameter[] paras
= new SqlParameter[ 1 ];
paras[
0 ] = new SqlParameter( " @ParentID " , DAHelper.ReadParam(parentID));
string strQuery = " SELECT * FROM [dbo].[Son] WHERE ParentID = @ParentID " ;
SqlDataReader reader
= DAHelper.ExecuteReader(strQuery, CommandType.Text, paras);
return Common.GetModels < Son > (reader);
}
#endregion

#region 更新数据

/// <summary>
/// 更新一条记录到Son表
/// </summary>
/// <param name="son"> Son对象 </param>
/// <returns> 更新所影响的行数 </returns>
public static int Update(Son son)
{
try
{
int returnNum = 0 ;
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ID " , DAHelper.ReadParam(son.ID)));
paras.Add(
new SqlParameter( " @ParentID " , DAHelper.ReadParam(son.ParentID)));
paras.Add(
new SqlParameter( " @SonCode " , DAHelper.ReadParam(son.SonCode)));
paras.Add(
new SqlParameter( " @SonName " , DAHelper.ReadParam(son.SonName)));

returnNum
= DAHelper.ExecuteNonQuery(
" UPDATE [dbo].[Son] SET [ParentID]=@ParentID, [SonCode]=@SonCode, [SonName]=@SonName " +
" WHERE [ID]=@ID " , CommandType.Text, paras);
return returnNum;
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}

#endregion

#region 删除数据
/// <summary>
/// 删除Son表数据
/// </summary>
/// <param name="id"> Son表主键ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int Delete( int id)
{
try
{
List
< SqlParameter > paras = new List < SqlParameter > ();
paras.Add(
new SqlParameter( " @ID " , DAHelper.ReadParam(id)));
return DAHelper.ExecuteNonQuery( " DELETE FROM [dbo].[Son] WHERE ID=@ID " , CommandType.Text, paras);
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 删除指定了主表ID且子表ID集合为lstSonID的记录
/// </summary>
/// <param name="lstSonID"> 子表ID集合 </param>
/// <param name="parentID"> 主表ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int DelSonExt(IList lstSonID, int parentID)
{
try
{
string notInString = " 0 " ;
for ( int i = 0 ; i < lstSonID.Count; i ++ )
{
notInString
+= " , " + lstSonID[i].ToString();
}
return DAHelper.ExecuteNonQuery( string .Format( " DELETE FROM [dbo].[Son] WHERE ParentID={1} AND ID NOT IN ({0}) " , notInString, parentID));
}
catch (SqlException ex)
{
throw new Exception(ex.Message);
}
}
#endregion
}
}

 

OK!数据访问层也好了,这里的东西就不一一介绍了,大家都看的明白的。

到这里,大部分与业务无关的东西全部写好了,下面就是业务逻辑层了,这是核心部分,对于一个大的项目来时,这里的代码最多,但是对于小的项目来说,这里只是起到传递的作用,这个简单的DEMO就是如此,就是一个主子表的保存业务,其他的就没什么了,呵呵…

ParentObject.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Parent表的业务逻辑层
* 主要功能:Parent表的业务逻辑层
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;
using DAL;
using System.Data;
using System.Collections;

namespace BLL
{
/// <summary>
/// Parent表的业务逻辑层
/// </summary>
public class ParentObject
{
#region 新增数据
/// <summary>
/// 新增一条记录到Parent表
/// </summary>
/// <param name="parent"> Parent对象 </param>
/// <returns> 主键标识 </returns>
public static int Create(Parent parent)
{
if (parent == null )
{
throw new Exception( " parent对象不能为空! " );
}
try
{
int id = 0 ;
id
= ParentManager.Create(parent);
foreach (Son son in parent.Sons)
{
son.ParentID
= id;
son.ID
= SonManager.Create(son);
}
return id;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion

#region 查询数据
/// <summary>
/// 查询全部Parent表数据
/// </summary>
/// <returns> Parent全部结果集 </returns>
public static DataSet Read()
{
return ParentManager.Read();
}

/// <summary>
/// 查询全部Parent表数据
/// </summary>
/// <typeparam name="T"> Parent对象 </typeparam>
/// <returns> Parent全部结果集 </returns>
public static IList < Parent > GetModels()
{
return ParentManager.GetModels();
}
/// <summary>
/// 查询主键ID为id的Parent表及其子表记录
/// </summary>
/// <typeparam name="T"> Parent对象 </typeparam>
/// <param name="id"> Parent表主键ID </param>
/// <returns> 主键ID为id的Parent表记录 </returns>
public static Parent GetModel( int id)
{
if (id <= 0 )
{
throw new Exception( " id不能小于或等于0! " );
}
Parent parent
= new Parent();
parent
= ParentManager.GetModel(id);
IList
< Son > sons = SonManager.GetModels(id);
parent.Sons
= sons.ToList < Son > ();
return parent;
}
#endregion

#region 更新数据
/// <summary>
/// 更新一条记录到Parent表及其子表
/// </summary>
/// <param name="parent"> Parent对象 </param>
/// <returns> 更新所影响的行数 </returns>
public static int Update(Parent parent)
{
if (parent == null )
{
throw new Exception( " parent对象不能为空! " );
}
try
{
int rowCount = 0 ;
rowCount
= ParentManager.Update(parent); // 更新主表数据
IList lstSonID = new ArrayList();
foreach (Son son in parent.Sons)
{
if (son.ID == 0 ) // 新增子表数据
{
son.ParentID
= parent.ID;
son.ID
= SonManager.Create(son);
}
else // 更新子表数据
{
SonManager.Update(son);
}
lstSonID.Add(son.ID);
}
SonManager.DelSonExt(lstSonID, parent.ID);
// 删除子表数据
return rowCount;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion

#region 删除数据
/// <summary>
/// 删除主表ID为id的主表及其子表记录
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static int Delete( int id)
{
if (id <= 0 )
{
throw new Exception( " id不能小于或等于0! " );
}
// 删除子表
SonManager.DeleteByParentID(id);
return ParentManager.Delete(id);
}
#endregion
}
}

 

SonObject.cs代码:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#region Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
/*
*******************************************************************
* 创 建 人:ZXZ
* 创建日期:2010-07-31
*
* 类 名 称:Son表的业务逻辑层
* 主要功能:Son表的业务逻辑层
*
* 最后修改:
* 修改日期:
* 修改内容:
*
*******************************************************************
*/
#endregion Copyright (c) 2002-2010 Shanghai Kundi Soft Inc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;
using DAL;
using System.Data;
using System.Collections;

namespace BLL
{
/// <summary>
/// Son表的业务逻辑层
/// </summary>
public class SonObject
{
#region 新增数据
/// <summary>
/// 新增一条记录到Son表
/// </summary>
/// <param name="son"> Son对象 </param>
/// <returns> 主键标识 </returns>
public static int Create(Son son)
{
if (son == null )
{
throw new Exception( " son对象不能为空! " );
}
return SonManager.Create(son);
}
#endregion

#region 查询数据
/// <summary>
/// 查询全部Son表数据
/// </summary>
/// <returns> Son全部结果集 </returns>
public static DataSet Read()
{
return SonManager.Read();
}

/// <summary>
/// 查询主表ID为parentID的子表集合
/// </summary>
/// <param name="parentID"> 主表主键ID </param>
/// <returns> 主表ID为parentID的子表集合 </returns>
public static IList < Son > GetModels( int parentID)
{
if (parentID <= 0 )
{
throw new Exception( " parentID不能小于或等于0! " );
}
return SonManager.GetModels(parentID);
}
#endregion

#region 更新数据
/// <summary>
/// 更新一条记录到Son表
/// </summary>
/// <param name="son"> Son对象 </param>
/// <returns> 更新所影响的行数 </returns>
public static int Update(Son son)
{
if (son == null )
{
throw new Exception( " son对象不能为空! " );
}
return SonManager.Update(son);
}
#endregion

#region 删除数据
/// <summary>
/// 删除Son表数据
/// </summary>
/// <param name="id"> Son表主键ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int Delete( int id)
{
if (id <= 0 )
{
throw new Exception( " id不能小于或等于0! " );
}
return SonManager.Delete(id);
}
/// <summary>
/// 删除指定主表的子表数据
/// </summary>
/// <param name="parentID"> 主表主键ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int DeleteByParentID( int parentID)
{
if (parentID <= 0 )
{
throw new Exception( " parentID不能小于或等于0! " );
}
return SonManager.DeleteByParentID(parentID);
}
/// <summary>
/// 删除指定了主表ID且子表ID集合为lstSonID的记录
/// </summary>
/// <param name="lstSonID"> 子表ID集合 </param>
/// <param name="parentID"> 主表ID </param>
/// <returns> 删除所影响的行数 </returns>
public static int DelSonExt(IList lstSonID, int parentID)
{
if (lstSonID == null )
{
throw new Exception( " 子表ID集合不能为空! " );
}
if (parentID == 0 )
{
throw new Exception( " 主表主键parentID不能为0! " );
}
return SonManager.DelSonExt(lstSonID, parentID);
}
#endregion
}
}

 

到这的时候就全部把三层里面的2层全部建好了,剩下的就是界面层了,我这里用的是Developer Express第三方控件,大家如果知道的话就比较简单了,不知道的也可以看,很简单,可以去网上下这个第三方控件,功能很强大…,这里就新建2个界面,一个是主表的List列表界面,一个是主表及其子表的Detail明细界面。

列表界面如图:

2010080112313330.jpg

明细界面如图:

 

2010080112320966.jpg

http://files.cnblogs.com/zxz414644665/ThreeTierDemo.rar

以上链接为VS2008的解决方案打包。

到此为止,全部结束,源代码附上。

 

转载于:https://www.cnblogs.com/zxz414644665/archive/2010/08/01/1789867.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值