biubiubiuBui cb064767a2 | ||
---|---|---|
src | ||
LICENSE | ||
README.md |
README.md
基于C语言实现的超市管理系统
1 需求分析
超市随着市场经济和现代信息技术的的发展,不可必要的要卷入信息现代化的大潮,如何使用现代化的工具,使企业和经营者个人在最小的投入下获取最大的回报,成为每一个人的梦想。因此,在超市管理中引进现代化的办公软件,就成为时下最好的解决办法。使用软件办公,不仅能使经营者的劳力资本减少,同时能使超市的管理更规范更合理,解决了超市中用于管理进出货以及购买、库存等众多繁琐、工作量巨大从而导致耗费人员过多,超市经营紊乱等众多问题。
1.1 主要功能
-
超级管理员模块:(需帐号登录)
- 添加管理员
- 删除管理员
-
管理员模块:(需帐号登录)
- 商品信息录入(编号、名称、单价、库存)
- 商品信息修改(修改商品的各种信息)
- 商品信息查询(根据所输入的商品名字,编码查询库存信息)
- 商品信息删除(从商品文件中删除商品信息)
- 商品信息排序(按编号,单价,库存3种模式进行排序)
- 输出商品全部库存信息
- 删除普通用户功能(管理员有权限删除普通用户帐号)
-
普通用户模块:(需帐号登录)
- 新用户注册
- 用户登录:
- 商品查询
- 商品排序
- 输出商品全部库存信息
- 购买商品(通过用户余额来进行购买)
- 充值(通过输入充值卡卡号对用户余额充值)
- 修改用户密码
1.2 运行环境
-
操作系统:Windows NT/2000/XP/VISTA/WIN7/WIN8/WIN10
-
开发平台:Microsoft Visual Studio 2012
1.3 文件说明
-
程序源代码(超市管理系统.cpp)
-
程序运行文件(超市管理系统.exe)
-
管理员信息(管理员信息.txt)
-
普通用户信息(普通用户信息.txt)
-
商品信息(商品信息.txt)
2 总体方案设计
2.1 设计方案
整个超市管理系统分为3个模块,超级管理员+管理员+普通用户,其中:
-
管理员可以实现商品信息的录入,修改,查询等管理操作,同时还拥有对普通用户帐号的管理
-
超级管理员是最高执行者,拥有对管理员帐号的操作权限,可以对管理员帐号进行添加或删除
-
普通用户模块,由于考虑到该程序的真实性,所以实现了普通用户的注册和登录功能,用户要进行购物,必须使用帐号(可自行注册,无须经过管理员),其中普通用户具有商品查询等一部分功能。特色功能是具有帐号余额功能,同时购物可以进行充值功能(输入充值卡卡号,类似于购买充值卡来充值)
2.2 主要结构
-
超级管理员模块:(需帐号登录)
- 添加管理员
- 删除管理员
-
管理员模块:(需帐号登录)
- 商品信息录入(编号、名称、单价、库存)
- 商品信息修改(修改商品的各种信息)
- 商品信息查询(根据所输入的商品名字,编码查询库存信息)
- 商品信息删除(从商品文件中删除商品信息)
- 商品信息排序(按编号,单价,库存3种模式进行排序)
- 输出商品全部库存信息
- 删除普通用户功能(管理员有权限删除普通用户帐号)
-
普通用户模块:(需帐号登录)
- 新用户注册
- 用户登录:
- 商品查询
- 商品排序
- 输出商品全部库存信息
- 购买商品(通过用户余额来进行购买)
- 充值(通过输入充值卡卡号对用户余额充值)
- 修改用户密码
2.3 程序功能和流程图
由于本程序模块功能较多,有超级管理员,管理员和普通用户,共3个模式的功能,流程图较大,因此分为3个子图。
**超级管理员模块 **
**管理员模块 **
**普通用户模块 **
2.4 数据结构和算法的设计说明
本程序有3个数据结构:管理员,普通用户,商品共3个结构体。其中程序拥有超级管理员、管理员和普通用户共3种身份,运用链表来存储和读取所保存的信息。
2.4.1 结构体类型
一开始选择模块,输入帐号和密码,进行验证,是否正确。正确就进入功能模块。
typedef struct custom* cpointer;//结点指针类型
struct custom{
string custom_ID;//帐号
string custom_name;//姓名
string custom_mima;//密码
double money;//账户余额
cpointer next;
};
typedef cpointer clklist;//单链表类型,即头指针类型
其中,管理员、普通用户、商品都是定义结构体,而后进入系统,一开始便定义相对应的链表进行存储和获取已保存的信息。
2.4.2 算法设计
排序算法
for(int i=0;i<Goodnum;i++){
for(int j=Goodnum;j>=i+1;j--){
if(Go.Good[j].Good_ID<Go.Good[j-1].Good_ID)
{//比较编号大小,小的在前面,大的在后面
flag=1;
p=Go.Good[j];
Go.Good[j]=Go.Good[j-1];
Go.Good[j-1]=p;
}
}
通过对相邻2个商品的编号不断比较,排序,运用2个for循环,比较编号大小,小的在前面,大的在后面。不断变换,最终排序完成。
2.5 程序关键源代码说明
程序中拥有3个身份:超级管理员,管理员,普通用户。不同身份之间函数都差不多,因此将函数直接展示,不说明为哪个身份的权限功能。
custom_ender函数:登录验证函数。对输入的帐号和密码进行验证检索,正确就进入对应的身份模块。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p,而后对p进行检索,如果p链表中的用户信息与输入的用户信息(帐号+密码)相同,就返回1;不同就显示“用户帐号不存在”,同时返回0。
int custom_ender(clklist &head,string ID,string mima){
cpointer p;
p=head;
while(p!=NULL) {
if(p->custom_ID==ID&&p->custom_mima==mima) return 1;
else p=p->next;
}
cout<<"用户帐号不存在!"<<endl;
return 0;
}
custom_creat函数:注册函数。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p,而后输入注册用户的各种信息(帐号,密码,姓名),如果输入的帐号ID与已保存的用户帐号相同,就显示已存在,提示重新输入。最后将输入的新注册用户信息运用头插法插入,保存到”普通用户信息.txt”文件中保存
void custom_creat(clklist &head){
cpointer s,p;
string ID,name,mima;
int sign=1,flat=1;
while(sign!=0){
flat=1;
cout<<"请输入用户帐号"<<endl;
cin>>ID;
p=head->next;
while(p!=NULL){
if(p->custom_ID==ID) flat=0;
p=p->next;
}
if(flat==0) {
cout<<"用户帐号已存在,请重新输入"<<endl;
continue;
}
cout<<"请输入用户密码"<<endl;
cin>>mima;
cout<<"请输入用户姓名"<<endl;
cin>>name;
s=new custom;
s->custom_ID=ID;
s->custom_name=name;
s->custom_mima=mima;
s->money=0;
s->next=head->next;//使用头插法建表
head->next=s;
buyernum++;//输入一个用户信息,buyernum自加1
custom_save(head);
cout<<"是否继续注册?<继续>请按1 <结束>请按0"<<endl;
cin>>sign;//while循环判断条件,所以不需要用if
}
}
custom_get函数:从文件获取用户信息函数。先定义一个普通用户结构体类型cpointer对象p,把包含普通用户全部信息的单链表head赋值给p, 而后运用一个for循环,将用户信息从“普通用户信息.txt“全部导入到p链表中,返回给系统。
clklist custom_get(clklist &buyer){
cpointer s,p;//s用于存储用户信息,p用于buyer的连接
string numname;
string ID,name,mima;
double money;
buyer->next=NULL;
p=buyer;
ifstream ifile("C:\\普通用户信息.txt",ios::in);
if(!ifile){
cerr<<"用户信息查询出错"<<endl;return 0;
}
ifile>>numname;
ifile>>buyernum;//从文件中提取用户个数,用于for循环
for(int i=1;i<=buyernum;i++){
ifile>>ID;
ifile>>name;
ifile>>mima;
ifile>>money;
s=new custom;
s->custom_ID=ID;
s->custom_name=name;
s->custom_mima=mima;
s->money=money;
s->next=p->next;
p->next=s;
}
buyer=p;
ifile.close();
return buyer;
}
Good_add函数:商品信息录入函数。把包含商品信息的链表Goods传入该函数,输入商品编号,if(Good_ender1(Goods,ID)==0)进行检索是否商品已存在,存在就提示重新输入,不存在就继续录入商品信息,导入到Goods链表中,最后运用Good_save(Goods)保存全部信息到“商品信息.txt”文件中。
void Good_add(sqlist &Goods){
string ID,name;
double piece;
int last,sign,flat=1;//last为商品库存,sign用于判断选择
fstream ifile("C:\\商品信息.txt",ios::in);
for(;flat!=0;) {
cout<<"请输入商品编号:";
cin>>ID;
if(Good_ender1(Goods,ID)==0) {
cout<<"请输入商品名称:";
cin>>name;
if(Good_ender2(Goods,name)==0) {
cout<<"请输入商品单价:";
cin>>piece;
cout<<"请输入商品数量:";
cin>>last;
Goods.Good[Goodnum].Good_ID=ID;
Goods.Good[Goodnum].Good_name=name;
Goods.Good[Goodnum].piece=piece;
Goods.Good[Goodnum].last=last;
Goodnum++;//添加完信息就自加1
Good_save(Goods);//添加完就保存至商品信息.txt
cout<<"是否继续录入?<继续>请按1 <结束>请按0"<<endl;
cin>>sign;
if(sign==0) break;
}
else {cout<<"商品名称已存在!<重新输入>请按1 <结束>请按0"<<endl;
cin>>flat;}
}
else {cout<<"商品编号已存在!<重新输入>请按1 <结束>请按0"<<endl;
cin>>flat;}
}
}
Good_change函数:商品信息修改函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种修改模式(按编号检索修改,还是按名称检索修改)。如果选择按编号检索修改,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后输入修改后的商品信息,保存至文件中;按名称检索修改类似。最后修改完后,会提示是否继续修改,如果不继续就返回用户功能界面,执行其他功能。
void Good_change(sqlist &Goods){
string ID,name;
int sign;//sign用于定位要修改商品的位置
int a,flat=1;//a用于switch
for(;flat!=0;){
cout<<"<输入要修改的商品编号>请按1 <输入要修改的商品名称>请按2"<<endl;
cin>>a;
if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;}
switch(a){
case 1:
{
cout<<"请输入商品编号:";
cin>>ID;
if(Good_ender1(Goods,ID)==1) {
sign=Good_locate1(Goods,ID);
cout<<"商品编号:"<<Goods.Good[sign].Good_ID<<endl;
cout<<"商品名称:"<<Goods.Good[sign].Good_name<<endl;
cout<<"商品单价:"<<Goods.Good[sign].piece<<endl;
cout<<"商品库存:"<<Goods.Good[sign].last<<endl;
cout<<"请输入修改后的信息:"<<endl;
cout<<"商品编号:";
cin>>Goods.Good[sign].Good_ID;
cout<<"商品名称:";
cin>>Goods.Good[sign].Good_name;
cout<<"商品单价:";
cin>>Goods.Good[sign].piece;
cout<<"商品库存:";
cin>>Goods.Good[sign].last;
Good_save(Goods);//保存信息
cout<<"修改成功"<<endl;
}
else cout<<"商品不存在!"<<endl;
break;
}
case 2: 大致与编号模式相同
else cout<<"商品不存在!"<<endl;
break;
}
}//switch的
cout<<"<继续修改>请按1 <退出>请按0"<<endl;
cin>>flat;
}//for循环的
}
Good_inquire函数:商品信息查询函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种查询方式(按编号检索查询,还是按名称检索查询)。如果选择按编号检索查询,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后输出该商品信息的全部信息;按名称检索查询类似。最后查询完后,会提示是否继续查询,如果不继续就返回用户功能界面,执行其他功能。
void Good_inquire(sqlist &Goods){
string ID,name;
int a,sign,flat=1;
for(;flat!=0;){
cout<<"<按商品编号查询>请按1 <按商品名称查询>请按2"<<endl;
cin>>a;
if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;}
switch(a){
case 1:
{
cout<<"请输入商品编号:";
cin>>ID;
if(Good_ender1(Goods,ID)==1) {
sign=Good_locate1(Goods,ID);
cout<<"商品编号:"<<Goods.Good[sign].Good_ID<<endl;
cout<<"商品名称:"<<Goods.Good[sign].Good_name<<endl;
cout<<"商品单价:"<<Goods.Good[sign].piece<<endl;
cout<<"商品库存:"<<Goods.Good[sign].last<<endl;
}
else cout<<"商品不存在!"<<endl;
break;
}
case 2: 大致与编号模式相同
else cout<<"商品不存在!"<<endl;
break;
}
}//switch的
cout<<"是否继续查询?<继续>请按1 <结束>请按0"<<endl;
cin>>flat;
if(flat==0) break;
}//for循环的
}
Good_delete函数:商品信息删除函数。把包含商品信息的链表Goods传入该函数,考虑到用户可能只记得商品编号或者商品名称,因此编写了2种删除方式(按编号检索删除,还是按名称检索删除)。如果选择按编号检索删除,同样对编号进行检索,如果在Goods链表中找到该商品编号,就运用 sign=Good_locate1(Goods,ID);定位记录下该商品在文件中的位置,而后使用for(int i=sign; i<Goodnum; i++)将该位置后的商品全部前移1位,覆盖掉该位置,最后保存删除后的商品信息至“商品信息.txt”中;按名称检索删除类似。最后删除完后,会提示是否继续删除,如果不继续就返回用户功能界面,执行其他功能。
void Good_delete(sqlist &Goods){
int a,sign,flat=1;
string ID,name;
for(;flat!=0;){
cout<<"<输入要删除的商品编号>请按1 <输入要删除的商品名称>请按2"<<endl;
cin>>a;
if(a!=1&&a!=2) {cout<<"选择有误,请重新输入"<<endl;continue;}
switch(a){
case 1:
{
cout<<"请输入要删除的商品编号:";
cin>>ID;
if(Good_ender1(Goods,ID)==1){
sign=Good_locate1(Goods,ID);
for(int i=sign;i<Goodnum;i++){
Goods.Good[i]=Goods.Good[i+1];
}
Goodnum--;
Good_save(Goods);
cout<<"删除成功!"<<endl;
}
else cout<<"商品不存在!"<<endl;
break;
}
case 2: 大致与编号模式相同
else cout<<"商品不存在!"<<endl;
break;
}
}//switch的
cout<<"是否继续删除?<继续>请按1 <结束>请按0"<<endl;
cin>>sign;
if(sign==0) break;
}//for循环的
}
Good_range函数:商品信息排序函数。把包含商品信息的链表Go传入该函数,选择排序模式(按编号,单价,库存进行排序),运用2层for循环,使用冒泡法进行排序,从尾部向头部进行对比检索,小的放前面,大的放后面,排序完之后就将排序后的商品信息显示给用户;3种模式大致相同。最后排序完后,会提示是否继续执行,如果不继续就返回用户功能界面,执行其他功能。
void Good_range(sqlist Go){
Goods p;
p.piece=0;
p.last=0;
int a,flag=0,flat=1;
for(;flat!=0;){
cout<<"<按商品编号排序>请按1 <按商品单价排序>请按2 <按库存数量排序>请按3 <退出>请按0"<<endl;
cin>>a;
if(a!=0&&a!=1&&a!=2&&a!=3) {cout<<"选择有误,请重新输入"<<endl;continue;}
switch(a){
case 1:
{
for(int i=0;i<Goodnum;i++){
for(int j=Goodnum;j>=i+1;j--){
if(Go.Good[j].Good_ID<Go.Good[j-1].Good_ID){//比较编号大小,小的在前面,大的在后面
flag=1;
p=Go.Good[j];
Go.Good[j]=Go.Good[j-1];
Go.Good[j-1]=p;
}
}//jfor的
if(!flag) break;
}//ifor的
cout<<"商品编号"<<setw(10)<<"商品名称"<<setw(10)<<"商品单价"<<setw(10)<<"商品库存"<<endl;
for(int i=1;i<=Goodnum;i++){
cout<<Go.Good[i].Good_ID<<setw(13)<<Go.Good[i].Good_name<<setw(8)<<Go.Good[i].piece<<setw(10)<<Go.Good[i].last<<endl;
}
break;
}
case 2: 大致与编号模式相同
case 3: 大致与编号模式相同
case 0:return;
}//switch的
}//最外层for的
Good_buy函数:购买商品函数。把包含商品信息的链表Goods以及包含用户信息的链表head传入该函数,选择购买模式(输入编号或名称进行购买),如果输入的商品编号与Goods中的商品信息相同,就提示购买数量,这时如果购买数量超过库存数量会提示“库存不足”,然后重新输入;如果购买商品所支付的钱超过用户的余额,则提示“余额不足”,是否前往充值页面进行充值。充值模块下面会展示。购买完商品后,用户可以继续购买,也可以返回用户功能界面。
void Good_buy(sqlist &Goods,clklist &head,string cID){//cID为用户帐号
string ID,name;
int a,shu,sign,flat=1;
cpointer p;
p=custom_locate(head,cID);
for(;flat!=0;){
cout<<"<输入商品编号购买>请按1 <输入商品名称购买>请按2"<<endl;
cin>>a;
if(a!=1&&a!=2) {cout<<"输入有误,请重新输入"<<endl;continue;}
switch (a)
{
case 1:
{
cout<<"请输入商品编号:";
cin>>ID;
if(Good_ender1(Goods,ID)==1)
{
sign=Good_locate1(Goods,ID);
cout<<"请输入购买数量:";
cin>>shu;
if(shu<=Goods.Good[sign].last){
if(p->money<Goods.Good[sign].piece*shu)
{cout<<"余额不足,请充值!"<<endl;
cout<<"是否前往充值?<充值>请按1 <否>请按0"<<endl;
cin>>flat;
if(flat==0) break;
if(flat==1) return;}
Goods.Good[sign].last=Goods.Good[sign].last-shu;
cout<<"购买成功"<<endl;
p->money=p->money-Goods.Good[sign].piece*shu;//账户余额减少,扣费成功
custom_save(head);
cout<<"账户余额:"<<p->money<<endl;
Good_save(Goods);
}
else cout<<"库存不足!"<<endl;
}
else cout<<"找不到相应商品,购买失败"<<endl;
break;
}
case 2:与编号模式类似
}//switch的
cout<<"是否继续购物?<继续>请按1 <结束>请按0"<<endl;
cin>>flat;
if(flat==0) break;
}//for的
}
custom_addmoney函数:余额充值函数。余额是用户帐号中的一个成员,初始为0,用户在购物的时候余额会减少,如果余额不足就无法进行购物,需要进行充值,充值是输入系统给定的充值卡卡号进行充值,这是本系统的一大亮点。把包含用户信息的链表head传入该函数,运用 p=custom_locate(head,ID);定位是哪个用户的帐号要进行充值,其中,系统设定了2种充值卡“asd500”和“asd1000”分别可以充值500和1000元,这类似与用户购买不同的充值卡给自己的账户进行充值。用户输入充值卡卡号,进行检索是否与系统设定的充值卡卡号相同,如果相同就充值相应的金额;如果不同,就提示“充值卡无效”。最后充值后,用户可以选择继续充值或者返回用户功能界面进行购物等其他操作。
void custom_addmoney(clklist &head,string ID){
cpointer p;
int sign=1;
p=custom_locate(head,ID);
string acard,card1="asd500",card2="asd1000";
while(sign!=0){
cout<<"请输入您获得的充值卡卡号:";
cin>>acard;//acard是用户获得的充值卡
if(acard!=card1&&acard!=card2) cout<<"充值卡无效"<<endl;
if(acard==card1)
{
p->money+=500;
cout<<"充值成功!"<<endl;
cout<<"账户余额:"<<p->money<<endl;
};
if(acard==card2)
{
p->money+=1000;
cout<<"充值成功!"<<endl;
cout<<"账户余额:"<<p->money<<endl;
};
custom_save(head);//充值成功
cout<<"是否继续充值?<继续>请按1 <结束>请按0"<<endl;
cin>>sign;//while循环判断条件,所以不需要用if
}
3 程序功能测试
一开始进入系统,初次使用会提示文件打开失败,是正常的,不影响功能。由于原本的“管理员信息.txt”“普通用户信息.txt”“商品信息.txt”是空的,当录入信息就不会有提示了。进入身份选择(都要帐号和密码)
选择1进入超级管理员,(帐号:asd,密码123),先添加管理员。
选择1,添加管理员信息(帐号+密码+姓名),添加完后可以选择继续添加或返回
选择2,输入要删除的管理员帐号,直接删除管理员
添加完管理员后,可返回主菜单,进入管理员模式,输入刚刚添加的管理员帐号+密码,进入管理员模式
功能1,进入商品录入功能,输入商品的信息(编号,名称,单价,库存),当录入成功之后,管理员可以选择继续录入或返回(该模块当录入编号和名称和已录入的信息相同会提示出错,重新录入)
功能2,可进行商品修改,有2种模式进行选择,输入商品编号101后,显示“商品信息.txt“文件中的商品信息,而后管理员可以输入修改后的信息
功能3,可以进行商品信息查询,可以查询到刚刚修改的联想笔记本
功能4,可以进行删除已录入的商品信息,例如,删除刚录入的联想笔记本
删除后,进入查询功能查看联想笔记本,不存在,表明删除成功~ ~
功能5,进行已录入商品信息排序,可选择(编号,单价,库存)进行从小到大排序,编号也是可以的
功能6,输出全部商品信息
功能7,删除普通用户,如果已经有普通用户,只需要输入普通用户的帐号就可以直接删除
进入普通用户模块,如果没有帐号是无法查看和购物的,因此消费者可以自行注册
注册完,就可以登录进入用户模块进行购物了
其中,商品查询,排序,库存是和管理员一样的,就不展示了
功能4,购买商品,一开始,由于没充值时,用户余额为0,余额不足,无法购买,用户可以返回,进行充值后购买。如果充值后,余额充足就可以购买了,购买后,余额相应减少
这里我先前往充值2000元,后购买如下,主机单价50,购买后余额为1950,扣费成功
功能5,用户可以随时修改自己的账户密码,保护自己的财产
功能6,就是充值了,输入系统给定的充值卡卡号,有(asd500和asd1000)
由于刚余额1950,现在输入卡号asd1000,成功充值1000,剩余2950
4 总结
这次选择了做“超市管理系统”,在完成基本功能之后,觉得要真正实现成功的超市管理系统,必须要有个人的帐号,因此增加了普通用户注册和帐号模式,同时管理员和超级管理员也都是用帐号+密码进入。普通用户可以自行注册,拥有自己的私人帐号。同时,超市管理系统普通用户在进行购买之后,应该是要有余额的,因此添加了余额成员。拥有余额成员之后,就想到,用户需要购买东西,余额不足就需要进行充值,为了实现真实性,就选定,用户需要输入充值卡卡号进行充值。最终完美实现。
这个系统,是使用链表实现的,由于之前的大作业是使用文件流,不是使用链表,因此这次的大作业就决定说要使用链表来实现。在编程过程中,也发现了很多的bug,最终还是一一解决。感觉自己的编程能力在不断的提高,无论是什么bug都可以自行调试解决。
同时,在思考程序的框架功能时,也逐渐重视用户体验,人机交互。编写大作业,不再只是仅仅满足基本功能,在基本功能上,还添加其余用户体验好的功能(比如帐号登录,充值等等功能),感觉大作业让我学会了很多。