摘 要
随着软件技术的不断进步和发展,信息化的管理方式越来越广泛的应用于各个领域,对于任何网站系统的管理来说开发一套现代化的成员管理软件是十分必要的。通过这样的软件系统,可以做到成员的规范管理和快速查询,从而减少管理方面的工作量。有效的管理所有成员的信息就是成员管理系统完成的功能。销售管理系统是使用MS.NET平台中的ASP.NET开发基于B/S体系结构的Web应用程序,在Microsoft Visual Studio .NET 环境下,使用 C# 编程语言并结合Microsoft SQL Server 2000 数据库开发出一套网络版的销售管理系统。该系统由前端输入和后端管理组成。前端实现了用户注册,用户登录,购物车,定单查询,商品浏览(包括热门商品和新到商品),商品搜索等。后台实现了用户信息管理,管理员信息管理,商品信息管理,销售管理。通过这个系统,可以大大的提高网络管理者的工作效率和工作精度。
关键词 **:**网络商店;销售管理系统;模块;控件;C#.NET
1.4相关软件及技术介绍
1 .4.1 ASP.NET技术
ASP.NET 是一种建立在通用语言上的程序构架,能被用于一台Web服务器来建立强大的Web应用程序。ASP.NET构架是可以用Microsoft(R)公司最新的产品 Visual Studio开发环境进行开发ASP.NET是基于通用语言的编译运行的程序,可以使它运行在Web应用软件开发者的几乎全部的平台上。通用语言的基本库,消息机制,数据接口的处理都能无缝的整合到ASP.NET的Web应用中。
1 .4.2 SQL Server
SQL Server 是一个具备完全 Web 支持的数据库产品,提供了对可扩展标记语言 (XML) 的核心支持以及在 Internet 上和防火墙外进行查询的能力,提供了以 Web 标准为基础的扩展数据库编程功能。
1 .4.3 Visual Studio.net 2003
它是Microsoft推出.NET应用程序开发工具。它易学易用的特性得到很多的好评。Microsoft又推出新版的.NET应用程序开发工具 Visual Studio.NET 2005,加入更多的好用功能,是.net的好开发工具。
2.项目模块及框图
2.1 系统功能模快设计
系统主体采用B/ S(Browser/ Server ,浏览器/ 服务器) 结构,即采用目前分布式系统流行的3 层软件结构,即在传统的客户和服务器之间加入应用服务器(Application server) ,3 层即是表现层(浏览器) 、业务逻辑层(Web 服务器) 、数据层(数据服务器) ,系统简图如图2-1所示。数据服务器与Web 服务器是完全分开的,分开之后的3 层软件结构功能明确:客户层只提供应用程序的用户界面,负责与用户交互;业务逻辑层是应用系统的关键,它负责处理所有用户请求,进行具体的运算和决定程序的流程,并把处理结果返回给表现层;服务器层仍然提供的是数据库支持、维护和更新应用程序的数据。
2.2 网络销售管理流程图
图1 网络销售管理系统数据流程
2.3网络销售管理系统模块组织图
图2A系统模块组织图
图2B系统模块组织图
4.模块设计、分析、开发
4.1主页面设计
主页面是直接展示给用户的部分。在这一模块中,主要包括以下自定义控件和页面的实现:
页面头部控件(HeadMenu.ascx):主要包括登录链接和搜索框
商品分类导航控件(CategoryList.ascx):显示所有商品的列表,作为页面的左侧导航目录。
4.1.1页面头部控件设计
页面头部控件是为了方便用户快速导航到某个页面的,在HeaderMenu.ascx的设计中,具有技巧性的地方是如何展示给登录用户和匿名用户不同的导航条,为了区别登录用户和匿名用户,在HeaderMenu.ascx中将匿名用户所拥有的链接放在一个Span容器中,并将Span设为"Runat=Server",这样就方便在代码中对去是否可见进行控制。同样,将登录用户需要的链接也放在另一个Span中。另
外,"搜索"也是一个超级链接,但它并非链接到某个Url。而是执行一条JavaScript语句"javascript:searh.submit()",即把页面提交。如下图所示:
图3登录用户导航条 图 4匿名用户导航条
控件代码的实现
在HeaderMenu的代码中,主要是判断用户的情况并控制Span容器的可见性。在HeaderMenu.ascx.cs中定义了下面的方法:
void showButton()
{
//是否是匿名用户
if (Request.IsAuthenticated != true)
{
//登录用户区域不可见
areaLoggedIn.Visible = false;
//匿名用户区域可见
areaLoggedOut.Visible = true;
}
else
{
areaLoggedIn.Visible = true;
areaLoggedOut.Visible = false;
}
}
这样在窗体加载即执行Pvage_Load()是调用上面的方法就可以实现效果了:
Private void Page_Load(object sender,System.EventArgs e)
{
showButton();
}
4.1.2 商品分类导航控件的设计
该控件显示所有商品的分类,单击目录中某个商品类别是将显示相应类别的商品列表页面。在CategoryList.ascx中主要用到了DataList控件,它用来绑定数据源。
控件代码的实现
private void Page_Load(object sender, System.EventArgs e)
{
// 设置目录的选定项
string selectionID = Request.Params["selection"];
if ( selectionID != null)
{
MyList.SelectedIndex = Int32.Parse(selectionID);
}
//将数据源绑定至DataList控件
MyList.DataSource = BLL.Product.GetCategoryList();
MyList.DataBind();
}
可以看到,MyList的绑定数据源是方法GetCategoryList()的返回值,这个方法在BLL层中的Product类中,他调用数据库的存储过程GetCatergoryList。
4.2****商品信息模块页面
分类显示商品显示某种类型的所有商品。
ProductList.aspx页面的布局和首页基本相似,不同的是,在页面的中心位置放置了一个Reperter控件来绑定数据源,Repeater控件中用一个表格的第一行作为它的HeaderTemplate,而ItemTempmlate项中绑定了数据源的相应字段。"购物"也是通过超级链接来实现页面的传递。主要代码如下:
//页的大小
private static int PageSize = 5;
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
{
//显示第一页的记录
ShowResult(0, PageSize);
}
}
void ShowResult(int pageIndex, int pageSize)
{
/绑定Repeater控件
products.DataSource = BLL.Product.GetProductsByCategory(int.Parse(Request.QueryString["categoryId"](pageSize, pageIndex);
products.DataBind();
//调用Product类中的方法获得该类商品的总数
int resultCount = BLL.Product.GetProductCountByCategory(int.Parse(Request.QueryString["categoryId"]));
int count;
//如果查询结果总数是页大小的整数倍
if (resultCount%PageSize == 0)
{
count = resultCount/PageSize;
PageCount.Text = count.ToString();
}
else
{
count = resultCount/PageSize+1;
PageCount.Text = count.ToString();
}
page.Items.Clear();
//绑定页码到DropDownList控件
for(int i=0; i<count; i++)
{
ListItem item = new ListItem((i+1).ToString(), i.ToString());
page.Items.Add(item);
}
page.SelectedIndex = pageIndex;
}
4.3****用户信息管理模块设计
4.3.1登录页面设计
图5 用户登录界面
在这个系统中采用Froms验证方式,当自定义的验证程序确认用户身份时,可以让Froms验证系统发出Cookie,Cookie中除了包含验证票据之外,还可以通过程序写入被验证用户的标识信息,比如用户编号,然后使用该Cookie访问个人的信息。Forms验证方式还可以保证有权限要求的页面无法被匿名用户访问。例如,密码修改页面(ChangePwd.aspx)不能被匿名用户访问,要达到上诉目标,需要在配置文件Web。Config里面创建一个项。代码如下:
<!验证方式为Forms>
<authentication mode="Forms">
<formsname="eshop" loginUrl="signIn.aspx"protecon="all"path="/"/>
</authentication>
需要注意的是,<forms>标记中,name的值为验证系统所发出的Cookie的名称,loginUrl表示匿名用户被重定向到的页面的地址。如何防止ChangPwd不被匿名用户直接访问呢,也需要创建下面的项:
<location path="ChangePwd.aspx">
<system.web>
<authorization>
<!--拒绝匿名用户-->
<deny user="?"/>
</authorization>
</system.web>
</location>
同样,用户可以注销验证信息,注销页面(SignOut.aspx)代码如下:
private void Page_Load(object sender, System.EventArgs e)
{
//注销验证信息
System.Web.Security.FormsAuthentication.SignOut();
//清空Session
Session.Clear();
//返回首页
Response.Redirect("default.aspx");
}
4.3.2 注册页面的设计
注册新用户时候,仅需输入最基本的信息,个人详细资料在注册之后再进行修改,Register.aspx的界面主要是接收一些用户输入的文本框,以及相应的验证控件、"注册"按钮和显示提示信息的Lable控件。
图6 注册页面
代码的实现:通过存储过程AddNewUser实现注册的功能:
CREATE PROCEDURE AddNewUser
(
@username nvarchar(50),
@password nvarchar(50),
@question nvarchar(50),
@answer nvarchar(50),
@result int output
)
AS
/*是否存在相同的用户名*/
if not exists (SELECT * FROM USERINFO WHERE USERNAME=@USERNAME )
BEGIN
/*插入新的用户记录*/
INSERT INTO USERINFO (USERNAME, USERPWD, QUESTION, ANSWER)
VALUES (@USERNAME, @PASSWORD, @question, @answer)
/*将Result赋值为新添加用户的UserId*/
SELECT @result = SCOPE_IDENTITY()
END
ELSE
BEGIN
SET @RESULT = -1
END
该存储过程带有输出参数,如果有相同的用户存在,输出参数为-1,否则,输出的参数的值为该用户的UserID。在User类中定义方法AddNewUser()调用AddNewUser存储过程,
4.4****购物车功能的设计与实现
在前面的流程图中,我们可以看到这个购物流程是不允许匿名用户拥有购物车的,匿名用户注册并登录之后,才能使用购物车。登录用户的购物车编号CartID为用户编号。CartID生成过程中用到了Cookie,Cookie是用来保存个人信息的对象,它存在于客户端。针对购物车的功能,设计了ShoppingCart类,其中定义了GetShoppingCartID(),代码如下:
public String GetShoppingCartID()
{
HttpContext Context = HttpContext.Current;
// 如果该用户已经通过验证后登录了系统,
那么以该用户的UserID作为购物车ID
if (Context.User.Identity.Name != "")
{
Response.Redirect("/esop/SignIn.aspx");
}
if (Context.Request.Cookies["ShoppingCartID"] != null)
{
return Context.Request.Cookies["ShoppingCartID"].Value;
}
在数据库中定义了存储过程ShoppingCartAddItem,实现向购物车添加商品的功能,代码如下:
CREATE Procedure ShoppingCartAddItem
(
@CartID nvarchar(50),
@ProductID int,
@Quantity int
)
As
DECLARE @CountItems int
SELECT
@CountItems = Count(ProductID)
FROM
ShoppingCart
WHERE
ProductID = @ProductID
AND
CartID = @CartID
IF @CountItems > 0 /* 该购物车中已有该商品的记录,更新数量 */
UPDATE
ShoppingCart
SET
Quantity = (@Quantity + ShoppingCart.Quantity)
WHERE
ProductID = @ProductID
AND
CartID = @CartID
ELSE /* 该购物车中没有这个商品的记录,插入新记录 */
INSERT INTO ShoppingCart
(
CartID,
Quantity,
ProductID
)
VALUES
(
@CartID,
@Quantity,
@ProductID
)
GO
4.5 购物车的结算设计与实现
图 7 商品结算界面
如果用户的预存款金额不足够支付本次购物,则会出现"存款不足"的提示如果能够支付,则生成新的订单,实现预存款支付订单的存储过程代码如下:CREATE PROCEDURE PayOrder
@userId int,
@totalcost decimal,
@result int output
AS
DECLARE @tmp decimal
/*@tmp为当前用户预存款金额*/
SELECT @tmp = acount
FROM UserInfo
WHERE userID = @userId
/*如果预存款不足*/
IF @tmp <@totalcost
BEGIN
/*置标志为-1*/
SET @result = -1
END
/*预存款足够支付,扣除相应的金额*/
ELSE
BEGIN
UPDATE UserInfo
SET acount = acount -@totalcost
WHERE userId= @userId
/*置标志为1*/
SET @result = 1
END
GO
4.6****查询销售情况页面的设计
模块的查询支持按月查询、日查询。查询的结果是每种商品的相关的定单数、售出数量和销售收入。页面主要包括3个DropDownList,分别用来选择年、月、日,两个按钮分别进行按月查询和按日查询,以及显示查询的结果的DataGrid。页面第一次加载时,显示日期为当前日期,并绑定到当前的销售情况。
图8销售情况图
代码的实现
查询销售情况的存储过程定义为GetSails,有3个输入参数,分别为@year(年)、@month(月)、@day(日)。当@day为0时,表示查询月记录,否则为查询当日记录。
在adminDB类中定义GetSails()方法调用上面的GetSails存储过程,并返回记录集。代码如下:
public DataSet GetSails(string year, string month, string day)
{
SqlParameter[] para = {
new SqlParameter("@year", int.Parse(year)),
new SqlParameter("@month", int.Parse(month)),
new SqlParameter("@day", int.Parse(day))
};
return eshop.DAL.SQLHelper.ExecuteDataset(eshop.DAL.SQLHelper.CONN_STRING, CommandType.StoredProcedure, "GetSails", para);
}
在用户表示层,首先需要绑定选择日期的DropDownList。定义BindDate()方法,代码如下:
void BindDate()
{
//绑定年
for (int i=2007; i<2020; i++)
{
ListItem item = new ListItem(Convert.ToString(i),Convert.ToString(i));
Year.Items.Add(item);
}
//绑定月
for (int i = 1 ; i<13 ; i++)
{
ListItem item1 = new ListItem(Convert.ToString(i),Convert.ToString(i));
Month.Items.Add(item1);
}
//绑定日
for (int i=1; i<32; i++)
{
ListItem item2 = new;
Day.Items.Add(item2);
}
}
此外,定义绑定DataGrid的方法BindGrid():
void BindGrid(string year, string month, string day)
{
GridSails.DataSource = new AdminDB().GetSails(year, month, day);
GridSails.DataBind();
}
在页面加载时间处理方法Page_Load()中对数据进行绑定,并显示当前日期以及当日销售记录:
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
{
BindDate();
//绑定当天记录
BindGrid(DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString(),
DateTime.Now.Day.ToString());
//显示为当前日期
Year.SelectedValue = DateTime.Now.Year.ToString();
Month.SelectedValue = DateTime.Now.Month.ToString();
Day.SelectedValue = DateTime.Now.Day.ToString();
//插入日志
AdminDB.InsertAction("查看当日销售记录", System.DateTime.Now, User.Identity.Name);
}
}
最后,在两个按钮单击事件处理方法中添加绑定数据以及插入日志的代码:
//查询所选日期的月销售记录
private void QueryMonth_Click(object sender, System.EventArgs e)
{
BindGrid(Year.SelectedValue, Month.SelectedValue, "0");
AdminDB.InsertAction("查看"+Year.SelectedValue+"年"+Month.SelectedValue+"月"
- "的销售记录", System.DateTime.Now, User.Identity.Name);
}
//查询所选日期的日销售记录
private void QueryDay_Click(object sender, System.EventArgs e)
{
BindGrid(Year.SelectedValue, Month.SelectedValue, Day.SelectedValue);
AdminDB.InsertAction("查看"+Year.SelectedValue+"年"+Month.SelectedValue+"月"
- Day.SelectedValue +"日的销售记录", System.DateTime.Now,User.Identity.Name
}