机房预约系统
1、机房预约系统需求
1.1系统简介
学校现有几个规格不同的机房,由于使用时经常出现"撞车"现象,现开发一套机房预约系统,解决这一问题。
1.2身份简介
分别有三种身份使用该程序
学生代表:申请使用机房
教师:审核学生的预约申请
管理员:给学生、教师创建账号
1.3机房简介
机房共有三间
1号机房: ---最大容量20人
2号机房 ---最大容量50人
3号机房 ---最大容量100人
1.4申请简介
申请的订单每周有管理员负责清空
学生可以预约未来一周内的机房使用,预约的日期为周一到周五,预约时需要选择预约时段(上午或者下午)
教师来审核预约,依据实际情况审核预约通过或者不通过
1.5系统具体需求
首先进入登录界面,可选登录身份有:学生代表、老师、管理员、退出
每个身份都需要进行验证后,进入子菜单:
- 学生需要输入:学号、姓名、登录密码
- 教师需要输入:职工号、姓名、登录密码
- 管理员需要输入:管理员姓名、登录密码
学生具体功能:
- 申请预约 --- 预约机房:选择日期、使用时段、预约机房号、生成记录
- 查看自身的预约 --- 查看自己的预约状态:日期、时段、机房号、预约状态
- 查看所有预约 --- 查看全部的(别人的+自己的)预约信息以及预约状态,依据别人的预约状态,更改或者调整自己的预约:日期、时段、学号、学生姓名、机房号、预约状态
- 取消预约 --- 取消自身的预约,自己预约成功或审核中的预约均可取消
教师的具体功能:
- 查看所有预约 --- 查看全部的预约信息以及预约状态
- 审核预约 --- 对学生的预约进行审核,学生取消的预约不会显示
- 注销登录 --- 退出登录
管理员的具体功能:
- 添加账号 --- 添加学生或者教师的账号,需要检测学生编号或者教师职工编号是否重复,需同步生成老师学生的信息写入文件中
- 查看账号 --- 可以选择查看学生或者教师的全部信息
- 查看机房 --- 查看所有机房的信息
- 清空预约 --- 清空所有记录
- 注销登录 --- 退出登录
预约的状态:审核中、预约成功、预约失败、已取消。
2、创建项目
2.1创建项目
打开vs,创建新项目,选择空项目,输入项目名称,选择项目位置进行创建
3、创建主菜单
设计主菜单,与用户进行交互
3.1菜单实现
在main函数中添加菜单提示
c++
void ShowMain()
{
cout << "====================== 欢迎来到青青草原机房预约系统 =========================" << endl;
cout << endl << "请选择您的身份" << endl;
cout << "\t\t------------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.学生代表 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.教 师 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.管 理 员 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.退 出 |\n";
cout << "\t\t| |\n";
cout << "\t\t------------------------------------\n";
cout << "请输入您的身份选择:" << endl;
}
使用\t 转义字符来规范格式。将菜单函数进行封装,在main函数中进行调用
c++
int cs = 0;//记录用户选择
while (1)
{
ShowMain();
cin >> cs;
switch (cs)
{
case 1://学生身份的菜单
cout << "这是学生" << endl;
break;
case 2://教师身份的菜单
cout << "这是教师" << endl;
break;
case 3://管理员身份的菜单
cout << "这是管理员" << endl;
break;
case 0://退出系统
cout << "退出成功!欢迎下次使用!" << endl;
break;
default:
cout << "输入错误!请重新选择!" << endl;
system("pause");//按任意键继续
system("cls");//清屏操作
break;
}
}
但是目前还没有写各个子菜单,所以显示的还是原来的主菜单,后面完善各子菜单。
4、退出功能实现
在main函数中,分支0处添加退出程序的代码:
c++
case 0://退出系统
system("pause");//按任意键继续
cout << "退出成功!欢迎下次使用!" << endl;
return 0;//退出程序
break;
5、创建身份类
- 在整个系统中,有三种身份,分别为:学生代表、老师、管理员
- 三种身份有共性也有特性,可以为三种身份抽象出一个身份基类identity;这个身份基类(父类)包含三者的共性:名字、密码,在登录时都要输入各自的用户名以及密码;特性:学生有学号,老师有职工号
在头文件下创建identity.h头文件,
c++
#pragma once//防止头文件重复包含
#include <iostream>
using namespace std;
//身份基类
class Identity
{
public:
virtual void operMenu() = 0;//登录子菜单接口
string m_Name;//用户名
string m_PassWord;//密码
};
使用多态技术,写一个纯虚函数 virtual void operMenu()=0;,子菜单函数,因为每一个身份进去后都有一个子菜单的接口,届时,用子类重写父类的这个接口,就可以实现每个身份的子菜单不同了;子类必须重写父类的纯虚函数,否则子类也是一个抽象类。
抽象类只需要有头文件即可,抽象类不需要源文件进行实现函数,子类需要写源文件实现各个功能函数
5.2学生类
5.2.1功能分析
学生类主要功能是可以通过类中成员函数实现预约机房的操作
学生类中主要的功能有:
- 显示学生操作的菜单界面
- 申请预约
- 查看自身预约
- 查看所有预约
- 取消预约
- 退出登录
5.2.2类的创建
在头文件以及源文件下创建student.h和student.cpp文件
c++
#pragma once
#include<iostream>
using namespace std;
#include"identity.h"
class Student:public Identity
{
public:
//默认构造函数
Student();//自身提供的默认构造
//有参构造函数
Student(int id, string name, string passWord);//创建一个学生的时候,将信息提供过来,让学生知道自己的信息
//菜单界面
virtual void operMenu();//父类中的纯虚函数,子类需要重写
//申请预约功能
void applyOder();
//查看自己预约
void showMyOrder();
//查看所有预约
void showAllOrder();
//取消预约
void cancelOrder();
//退出登录
void exit();
//析构函数
~Student();
int m_id;
};
#student.cpp文件
#include<iostream>
using namespace std;
#include"student.h"
//头文件中所有成员函数的实现
//默认构造函数
Student::Student()
{
}//自身提供的默认构造
//有参构造函数
Student::Student(int id, string name, string passWord)
{
//创建一个学生的时候,将信息提供过来,让学生知道自己的信息
}
//菜单界面
void Student::operMenu()
{
//父类中的纯虚函数,子类需要重写
}
//申请预约功能
void Student::applyOder()
{
}
//查看自己预约
void Student::showMyOrder()
{
}
//查看所有预约
void Student::showAllOrder()
{
}
//取消预约
void Student::cancelOrder()
{
}
//退出登录
void Student::exit()
{
}
//析构函数
Student::~Student()
{
}
5.3老师类
5.3.1功能分析
教师类主要功能是查看学生的预约,并进行审核
教师类的主要功能有:
- 显示教师操作的菜单界面
- 查看所有预约
- 审核预约
5.3.2类的创建
在头文件以及源文件下创建teacher.h和teacher.cpp文件
c++
#pragma once
#include<iostream>
using namespace std;
#include"identity.h"
//教师类
class Teacher :public Identity
{
public:
//默认构造函数
Teacher();
//有参构造
Teacher(int id, string name, string passWord);
//教师子菜单
virtual void operOrder();
//查看所有预约
void showApply();
//审核预约
void validApply();
//析构函数
~Teacher();
//教师ID
int m_EmpId;
};
#teacher.cpp文件
#include"teacher.h"
//源文件,实现头文件中的所有成员函数
//默认构造函数
Teacher::Teacher()
{
}
//有参构造
Teacher::Teacher(int id, string name, string passWord)
{
}
//教师子菜单
void Teacher::operOrder()
{
}
//查看所有预约
void Teacher::showApply()
{
}
//审核预约
void Teacher::validApply()
{
}
//析构函数
Teacher::~Teacher()
{
}
5.4管理员类
5.4.1功能分析
管理员类主要功能是对学生和老师账户进行管理,查看机房信息以及清空预约记录
管理员类的主要功能有:
- 显示管理员操作的菜单界面
- 添加账号
- 查看账号
- 查看机房信息
- 清空预约记录
5.4.2类的创建
在头文件和源文件夹下创建manager.h和manager.cpp文件
c++
#pragma once
#include<iostream>
using namespace std;
#include"identity.h"
class Manager :public Identity
{
public:
//默认构造
Manager();
//有参构造
Manager(string name, string passWord);
//管理员子菜单
virtual void operMenu();
//添加账号
void addPerson();
//查看账号
void showPerson();
//查看机房信息
void showRoom();
//清空预约记录
void deleteRecord();
};
#manager.cpp文件
#include"manager.h"
//默认构造
Manager::Manager()
{
}
//有参构造
Manager::Manager(string name, string passWord)
{
}
//管理员子菜单
void Manager::operMenu()
{
}
//添加账号
void Manager::addPerson()
{
}
//查看账号
void Manager::showPerson()
{
}
//查看机房信息
void Manager::showRoom()
{
}
//清空预约记录
void Manager::deleteRecord()
{
}
6、登录模块
6.1全局文件添加
功能描述:
不同身份可能会用到不同的文件操作,管理员有一个管理员文件、学生有学生文件、老师有老师文件...;我们可以将所有的文件名重定义到一个全局的文件中,在我们使用文件时,使用宏定义的文件名即可,在头文件中添加globalFile.h文件。谁用文件名时,直接包含这个头文件即可,这样编译时就不用写后面的具体的文件名字了,使用宏定义的文件名。
c++
#pragma once
//管理员文件
#define ADMIN_FILE "admin.txt"
//学生文件
#define STUDENT_FILE "student.txt"
//教师文件
#define TEACHER_FILE "teacher.txt"
//机房信息文件
#define COMPUTER_FILE "computerRoom.txt"
//订单文件
#define ORDER_FILE "order.txt"
6.2登录函数封装
功能描述:根据用户的身份选择,进入不通过的身份登录,在预约系统的.cpp文件中添加全局函数 void LoginIn(string fileName,int type);参数:
fileName --- 操作的文件名,告诉用户操作的是那个文件,需要进行验证,去对应的文件进行操作
type --- 登录的身份(1代表学生,2代表老师,3代表管理员)
c++
void LoginIn(string fileName, int type)
{
Identity* person = NULL;//创建一个父类的指针,用于指向子类对象,即用户登录时临时指向这个用户,便于后续操作
//对文件进行操作,验证用户信息是否存在,读文件
ifstream ifs;
ifs.open(fileName, ios::in);
//判断文件是否存在
if (!ifs.is_open())
{
cout << "文件不存在!" << endl;
ifs.close();//文件不存在,关闭文件
return;//回到最开始
}
//准备需要比对的信息,接收用户需要输入的信息
int id = 0;
string name;
string password;
//判断用户身份
if (type == 1)
{
cout << "请输入学号" << endl;
cin >> id;
}
else if (type == 2)
{
cout << "请输入职工号" << endl;
cin >> id;
}
//输入共性,用户名和密码
cout << "请输入用户名" << endl;
cin >> name;
cout << "请输入密码" << endl;
cin >> password;
//接收完用户信息,去文件中验证信息
if (type==1)
{
//学生验证
}
else if (type == 2)
{
//教师验证
}
else if (type == 3)
{
//管理员验证
}
//其他情况
cout << "验证失败,用户名或密码错误!" << endl;
system("pause");//按任意键继续
system("cls");//清屏
return;
}
在主函数中的不同分支中,调用不同的登录接口
c++
switch (cs)
{
case 1://学生身份的菜单
LoginIn(STUDENT_FILE, 1);
break;
case 2://教师身份的菜单
LoginIn(TEACHER_FILE, 2);
break;
case 3://管理员身份的菜单
LoginIn(ADMIN_FILE, 3);
break;
case 0://退出系统
system("pause");//按任意键继续
cout << "退出成功!欢迎下次使用!" << endl;
return 0;//退出程序
break;
default:
cout << "输入错误!请重新选择!" << endl;
system("pause");//按任意键继续
system("cls");//清屏操作
break;
}
6.3学生登录实现
在student.txt文件中添加两条学生信息,用于测试。添加信息:
tex
1 懒羊羊 123
2 喜羊羊 456
三列数据分别为学号 姓名 密码。
进行验证时,若出现文件的中文字体出现乱码,点击打开文本文件,另存为,将文件编码格式改为ANSI

c++
//学生验证
//创建新的变量接收从文件中获取的ID,姓名,密码
int fId;
string fName;
string fPassword;
//对比两个变量,进行验证
//文件以空格为分割,当读文件遇到空格时,自动认为是到下一个信息了,所以直接读
while (ifs >> fId && ifs >> fName && ifs >> fPassword)
{
//与用户输入的信息进行对比
if (fId == id && fName == name && fPassword == password)
{
cout << "验证登录成功!" << endl;
system("pause");//按任意键清屏
system("cls");//清屏
//验证成功,创建学生对象,因为是本次登录临时会用到,所有new一个创建在堆区即可
person = new Student(id, name, password);//传入学生前面输入的信息
//进入到学生身份的子菜单
return;
}
}
6.4教师登录实现
在teacher.txt文件中添加两条老师信息,用于测试。
tex
01 慢羊羊 123
02 智羊羊 456
三列分别为 职工编号,老师姓名,登录密码
c++
//教师验证
//创建新的变量接收从文件中获取的ID,姓名,密码
int fId;
string fName;
string fPassword;
//对比两个变量,进行验证
//文件以空格为分割,当读文件遇到空格时,自动认为是到下一个信息了,所以直接读
while (ifs >> fId && ifs >> fName && ifs >> fPassword)
{
//与用户输入的信息进行对比
if (fId == id && fName == name && fPassword == password)
{
cout << "验证登录成功!" << endl;
system("pause");//按任意键清屏
system("cls");//清屏
//验证成功,创建老师对象,因为是本次登录临时会用到,所有new一个创建在堆区即可
person = new Teacher(id, name, password);//传入学生前面输入的信息
//进入到老师身份的子菜单
return;
}
}
6.5管理员登录实现
同上,添加一条管理员信息,在admin文件中
c++
//管理员验证
string fName;
string fPassword;
while (ifs >> fName && ifs >> fPassword)
{
if (fName == name && fPassword == password)
{
cout << "验证登录成功" << endl;
system("pause");
system("cls");
//创建管理员对象
person = new Manager(name, password);
//进入管理员的子菜单
return;
}
}
7、管理员模块
7.1管理员登录和注销
7.1.1构造函数
在manager类的构造函数中,初始化管理员信息。学生和老师的信息是由管理员添加的,所以应该先设置一下管理员的信息。
c++
//有参构造
Manager::Manager(string name, string passWord)
{
//初始化管理员信息
this->m_Name = name;
this->m_PassWord = passWord;
}
7.1.2管理员子菜单
机房预约系统中,当用户登录的身份是管理员,需要跳转到管理员子菜单,添加管理员子菜单接口。将不同的分支提供出来:
- 添加账号
- 查看账号
- 查看机房
- 清空预约
- 注销登录
实现注销功能,添加全局函数void managerMenu(Identity * &manager)
c++
void managerMenu(Identity*& manager)
{
while (true)
{
//调用管理员的子菜单
manager->operMenu();//多态,利用父类指针调用子类的接口,但公共的指针只能调用公共的功能,需要调用子类的接口还需要转回去
//将父类的指针转为子类的指针,就可以调用子类里面其他子类特有的接口
Manager* man = (Manager*)manager;//强制转换
//接收用户的操作选项
cout << "请输入操作选项:" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
cout << "添加账号" << endl;
man->addPerson();
}
else if (select == 2)
{
cout << "查看账号" << endl;
man->showPerson();
}
else if (select == 3)
{
cout << "查看机房信息" << endl;
man->showRoom();
}
else if (select == 4)
{
cout << "清空预约" << endl;
man->deleteRecord();
}
else
{
//其他选项,注销登录
delete manager;//销毁堆区的对象,就说退出登录成功
cout << "退出登录成功" << endl;
system("pause");
system("cls");
return;
}
}
}
7.1.3菜单功能实现
在manager.cpp文件中实现菜单界面函数
c++
void Manager::operMenu()
{
cout << "====================== 欢迎来到青青草原机房预约系统 =========================" << endl;
cout << endl << "====================== 您好!管理员" <<this->m_Name<<" ======================" << endl;
cout << "\t\t------------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.添加账号 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.查看账号 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.查看机房 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 4.清空预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.退出登录 |\n";
cout << "\t\t| |\n";
cout << "\t\t------------------------------------\n";
cout << "请输入您的操作选择:" << endl;
}
7.2添加账号
给学生或教师添加新的账号,添加时,要求学生学号不能重复,教师职工号不能重复
7.2.1
在Manager的添加账号的成员函数中实现函数的功能,代码如下:
c++
void Manager::addPerson()
{
cout << "请输入添加账号的类型" << endl;
cout << "1.添加学生" << endl;
cout << "2.添加老师" << endl;
int select = 0;
cin >> select;
string fileName;//操作的文件名
string tip;//提示操作的id号
ofstream ofs;//创建文件操作对象
if (select == 1)
{
fileName = STUDENT_FILE;
tip = "请输入学号:";
}
else
{
fileName = TEACHER_FILE;
tip = "请输入职工编号";
}
ofs.open(fileName, ios::out | ios::app);//利用追加的方式写入文件
int id;//学号职工号
string name;//用户名
string pwd;//密码
cout << tip << endl;
cin >> id;
cout << "请输入姓名" << endl;
cin >> name;
cout << "请输入密码" << endl;
cin >> pwd;
//向文件中添加数据
ofs << id << " " << name << " " << pwd << " " << endl;
cout << "添加成功!" << endl;
system("pause");
system("cls");
}
每次写是以追加的方式写入的,打开文件的方式除了写文件外,还需要以追加的方式写入
7.2.2去重操作
添加新账号时,如果是重复的学生编号,或是重复的教师职工编号,提示有误,已存在此编号
7.2.2.1读取信息
要去除重复的账号,首先要先将学生和教师的账号信息获取到程序中,后续再进行检测
在manager.h中,添加两个容器,分别用于存放从文件中读取的学生和老师的信息,方便后续进行检测;添加一个新的成员函数void initVector() ,用于初始化容器
c++
void Manager::initVector()
{
//先确保两个容器是空的,在进行初始化
vStu.clear();//容器清空
vTea.clear();
//读取信息
//学生
ifstream ifs;
ifs.open(STUDENT_FILE, ios::in);
if (!ifs.is_open())
{
cout << "文件读取失败" << endl;
return;
}
Student s;
//连续读取三个数据分别给s.m_id\ m_Name\m_PassWord
while (ifs >> s.m_id && ifs >> m_Name && ifs >> m_PassWord)
{
vStu.push_back(s);//取出里面的数据,写入容器中,使用尾插法
}
cout << "当前学生数量为:" << vStu.size() << endl;
ifs.close();
//老师
ifs.open(TEACHER_FILE, ios::in);
Teacher t;
while (ifs >> t.m_EmpId && ifs >> t.m_Name && ifs >> t.m_PassWord)
{
vTea.push_back(t);
}
cout << "当前老师数量为:" << vTea.size() << endl;
ifs.close();
}
7.2.2.2去重函数封装
在manager.h文件中添加成员函数 bool checkRepeat(int id,int type);,
在manager.cpp文件中实现成员函数 bool checkRepeat(int id,int type)
c++
//检测重复
bool Manager::checkRepeat(int id, int type)
{
if (type == 1)
{
//检测学生
for (vector<Student>::iterator it = vStu.begin(); it != vStu.end(); it++)
{
if (id == it->m_id)
{
return true;//重复
}
}
}
else
{
//检测老师
for (vector<Teacher>::iterator it = vTea.begin(); it != vTea.end(); it++)
{
if (id == it->m_EmpId)
{
return true;//重复
}
}
}
return false;//不重复
}
7.2.2.3添加去重操作
在添加学生编号或教师职工号时,检测是否有重复
c++
string errorTip;//重复错误的提示
cout << tip << endl;
//检测账号是否重复
while (true)
{
cin >> id;
bool ret;
ret = checkRepeat(id, select);
if (ret)
{
cout << errorTip << endl;
}
else
{
break;
}
}
7.2.2.4bug解决
虽然可以检测重复账号,但是刚添加的账号没有更新到本次程序运行的容器中,因此不会做检测;导致刚加入的账号的学生号和教师职工编号,本次程序运行时再次添加时依然可以重复。解决方案:在每次添加新账号时,重新初始化容器,在添加成功后,初始化容器
c++
//向文件中添加数据
ofs << id << " " << name << " " << pwd << " " << endl;
cout << "添加成功!" << endl;
system("pause");
system("cls");
ofs.close();
//初始化容器
this->initVector();
这样刚添加的账号就也不会重复了。此外还可以将新添加的账号添加进入容器,这样就不用重新初始化容器,全部重新写入了。
7.3显示账号
7.3.1显示功能实现
显示学生或者教师的信息。在manager的showPerson()成员函数中,实现显示账号的功能。
c++
//遍历查看学生容器
void printStudent(Student& s)
{
cout << "学号: " << s.m_id << "\t姓名: " << s.m_Name << "\t密码: " << s.m_PassWord << endl;
}
//遍历查看教师容器
void printTeacher(Teacher& t)
{
cout << "职工号: " << t.m_EmpId << "\t姓名: " << t.m_Name << "\t密码: " << t.m_PassWord << endl;
}
//查看账号
void Manager::showPerson()
{
cout << "请输入您要查看的类别" << endl;
cout << "1.查看学生账号" << endl;
cout << "2.查看老师账号" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
cout << "已有学生账号信息如下:" << endl;
for_each(vStu.begin(), vStu.end(), printStudent);
//for (vector<Student>::iterator it = vStu.begin(); it != vStu.end(); it++)
//{
// cout << "学号: " << it->m_id << "\t姓名: " << it->m_Name << "\t密码: " << it->m_PassWord << endl;
//}
}
else
{
cout << "已有教师账号信息如下:" << endl;
for_each(vTea.begin(), vTea.end(), printTeacher);
}
system("pause");//按任意键返回到上一单元
system("cls");
}
7.4查看机房
7.4.1添加机房信息
1号机房20台机器,2号机房50台机器,3号机房100台机器。将机房信息直接录入到computerRoom.txt文件中
tex
1 20
2 50
3 100
7.4.2机房类创建
在头文件下,创建新的文件computerRoom.h
c++
#pragma once
#include<iostream>
using namespace std;
//机房类
class ComputerRoom
{
public:
int m_ConId;//机房ID
int m_MaxNum;//机房最大容量
};
7.4.3初始化机房信息
将文件中的数据读取进入程序中,方便读取并使用,在manager.cpp文件中的有参构造中:
c++
//初始化机房信息
ifstream ifs;
ifs.open(COMPUTER_FILE, ios::in);
ComputerRoom com;
while (ifs >> com.m_ConId && ifs >> com.m_MaxNum)
{
vCom.push_back(com);
}
ifs.close();
cout << "机房的数量为:" << vCom.size() << endl;
7.4.4显示机房信息
遍历输出机房容器
c++
//查看机房信息
void Manager::showRoom()
{
cout << "当前机房信息如下:" << endl;
for (vector<ComputerRoom>::iterator it = vCom.begin(); it != vCom.end(); it++)
{
cout << "机房编号:" << it->m_ConId << "\t机房最大容量:" << it->m_MaxNum << endl;
}
system("pause");
system("cls");
}
7.5清空预约
清空生成的order.txt文件。在manager的cleanFile成员函数中添加如下代码:
c++
//清空预约记录
void Manager::deleteRecord()
{
cout << "清除记录不可撤销,是否清除!" << endl;
cout << "1.确定清除" << endl;
cout << "2.返回上一级" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
ofstream ofs(ORDER_FILE, ios::trunc);
ofs.close();
cout << "记录已清除!" << endl;
}
system("pause");
system("cls");
}
利用trunc方式打开文件就直接清空,再关闭文件即可
8、学生模块
8.1学生登录和注销
8.1.1构造函数
在student类的构造函数中,初始化学生信息
c++
//有参构造函数
Student::Student(int id, string name, string passWord)
{
//创建一个学生的时候,将信息提供过来,让学生知道自己的信息
//初始化属性
this->m_id = id;
this->m_Name = name;
this->m_PassWord = passWord;
}
8.1.2学生子菜单
在机房预约系统.cpp文件中,当用户登录的身份是学生时,需要进入学生子菜单接口,将不同分支提供出来。学生功能包含
申请预约、查看我的预约、查看所有预约、取消预约、退出登录 。添加全局函数void studentMenu(Identity*&manager)
c++
void Student::operMenu()
{
//父类中的纯虚函数,子类需要重写
cout << "====================== 欢迎来到青青草原机房预约系统 =========================" << endl;
cout << endl << "====================== 您好!" << this->m_Name << " ======================" << endl;
cout << "\t\t------------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1. 申 请 预 约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.查看自身预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.查看所有预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 4. 取 消 预 约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0. 退 出 登 录 |\n";
cout << "\t\t| |\n";
cout << "\t\t------------------------------------\n";
cout << "请输入您的操作选择:" << endl;
}
8.1.3菜单功能实现
c++
//学生子菜单
void studentMenu(Identity*& student)//传入父类指针
{
while (true)
{
//调用学生的子菜单
student->operMenu();//多态,利用父类指针调用子类的接口,但公共的指针只能调用公共的功能,需要调用子类的接口还需要转回去
//将父类的指针转为子类的指针,就可以调用子类里面其他子类特有的接口
Student* stu = (Student*)student;//强制转换
//接收用户的操作选项
cout << "请输入操作选项:" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
cout << "申请预约" << endl;
stu->applyOrder();
}
else if (select == 2)
{
cout << "查看我的预约" << endl;
stu->showMyOrder();
}
else if (select == 3)
{
cout << "查看所有预约" << endl;
stu->showAllOrder();
}
else if (select == 4)
{
cout << "取消预约" << endl;
stu->cancelOrder();
}
else
{
//其他选项,注销登录
delete student;//销毁堆区的对象,就说退出登录成功
cout << "退出登录成功" << endl;
system("pause");
system("cls");
return;
}
}
}
8.2申请预约
8.2.1获取机房信息
在申请预约时,学生可以看到机房的信息,因此,我们需要让学生获取到机房的信息,在学生类中添加新的成员函数
c++
vector<ComputerRoom>vCom;
在学生的有参构造函数中追加如下代码
c++
//初始化机房的信息
ifstream ifs;
ifs.open(COMPUTER_FILE, ios::in);
ComputerRoom com;
while (ifs >> com.m_ConId && ifs >> com.m_MaxNum)
{
vCom.push_back(com);//获取两个信息后,挨个放入容器中,从文件中获取放入到此次运行的容器中
}
8.2.2预约功能的实现
c++
//申请预约功能
void Student::applyOrder()
{
cout << "机房开放时间为:周一至周五" << endl;
cout << "请输入申请预约的时间:" << endl;
cout << "1、周一" << endl;
cout << "2、周二" << endl;
cout << "3、周三" << endl;
cout << "4、周四" << endl;
cout << "5、周五" << endl;
int date = 0;//日期
int interval = 0;//时间段
int room = 0;//机房号
while (true)
{
cin >> date;
if (date >= 1 && date <= 5)
{
break;//输入正确,退出输入循环,开始输入下一个操作
}
cout << "输入错误,请输入正确的日期" << endl;
}
cout << "请输入申请预约的时间段" << endl;
cout << "1、上午" << endl;
cout << "2、下午" << endl;
while (true)
{
cin >> interval;
if (interval >= 1 && interval <= 2)
{
break;//输入正确,退出输入循环,开始输入下一个操作
}
cout << "输入错误,请输入正确的时间段" << endl;
}
cout << "请选择机房:1 or 2 or 3" << endl;
//cout << vCom[0].m_ConId << "机房容量为:" << vCom[0].m_MaxNum << endl;
//cout << vCom[1].m_ConId << "机房容量为:" << vCom[1].m_MaxNum << endl;
//cout << vCom[2].m_ConId << "机房容量为:" << vCom[2].m_MaxNum << endl;
for (int i = 0; i < vCom.size(); i++)
{
cout << vCom[i].m_ConId << "号机房容量为:" << vCom[i].m_MaxNum << endl;
}
while (true)
{
cin >> room;
if (room >= 1 && room <= 3)
{
break;//输入正确,退出输入循环,开始输入下一个操作
}
cout << "输入错误,请输入正确的机房号" << endl;
}
//接收完学生申请信息,
cout << "预约成功,审核中" << endl;
ofstream ofs;
ofs.open(ORDER_FILE, ios::app);//以追加方式写入文件
ofs << "date:" << date << " ";
ofs << "interval:" << interval << " ";
ofs << "room:" << room << " ";
ofs << "stuId:" << this->m_id << " ";
ofs << "stuName:" << this->m_Name << " ";
ofs << "stutas:" << 1 << endl;//一条信息写完之后,进行换行
ofs.close();
system("pause");
system("cls");
}
8.3显示预约
8.3.1创建预约类
显示预约记录时,需要从文件中获取到所有记录,用以显示,创建预约的类管理记录以及更新审核状态;在头文件以及源文件下分别创建orderFile.h和orderFile.cpp文件
c++
//orderFile.h文件
#pragma once
#include<iostream>
using namespace std;
#include<map>
#include"globalFile.h"
#include<string>
#include<fstream>
class OrderFile
{
public:
//构造函数
OrderFile();
//更新预约记录
void updateOrder();
//记录当前预约条数
int m_Size;
//记录所有预约信息的容器,key表示记录的条数,value表示具体的一条预约信息
map<int, map<string, string>>m_OrderData;
};
//orderFile.cpp文件
#include"orderFile.h"
//构造函数
OrderFile::OrderFile()
{
ifstream ifs;
ifs.open(ORDER_FILE, ios::in);//开始读文件,以读文件的方式打开文件
string date;//日期
string interval;//时间段
string roomId;//机房编号
string stuId;//学生编号
string stuName;//学生姓名
string stutas;//预约的状态
this->m_Size = 0;//预约记录的条数
//读入信息分别给date、interval、roomId、stuId、stuName、stutas
while (ifs >> date && ifs >> interval && ifs >> roomId && ifs >> stuId && ifs >> stuName && ifs >> stutas)
{
string key;
string value;
map<string, string>m;
int pos = date.find(":");//4,于date而言,date:1;:在4
if (pos != -1)
{
key = date.substr(0, pos);//截从0开始,截4个字符
value = date.substr(pos + 1, date.size() - pos - 1);//截从5开始,size=6,pos=4,截取1个
m.insert(make_pair(key, value));
}
pos = interval.find(":");
if (pos != -1)
{
key = interval.substr(0, pos);
value = interval.substr(pos + 1, interval.size() - pos - 1);
m.insert(make_pair(key, value));
}
pos = roomId.find(":");
if (pos != -1)
{
key = roomId.substr(0, pos);
value = roomId.substr(pos + 1, roomId.size() - pos - 1);
m.insert(make_pair(key, value));
}
pos = stuId.find(":");
if (pos != -1)
{
key = stuId.substr(0, pos);
value = stuId.substr(pos + 1, stuId.size() - pos - 1);
m.insert(make_pair(key, value));
}
pos = stuName.find(":");
if (pos != -1)
{
key = stuName.substr(0, pos);
value = stuName.substr(pos + 1, stuName.size() - pos - 1);
m.insert(make_pair(key, value));
}
pos = stutas.find(":");
if (pos != -1)
{
key = stutas.substr(0, pos);
value = stutas.substr(pos + 1, stutas.size() - pos - 1);
m.insert(make_pair(key, value));
}
//将小的map容器放入到大的map容器中
this->m_OrderData.insert(make_pair(this->m_Size, m));
this->m_Size++;
}
ifs.close();
}
//更新预约记录
void OrderFile::updateOrder()
{
}
前面存储的预约信息可以理解为以键值对存在的,比如前面一个信息key 为date、interval、stuId、stuName、room,后面一个信息为value 。但是一条记录有很多个键值对,这样,写一个嵌套容器 map<int,map<string,string>> ,第一个容器为int和map的容器记录文件中的多条记录,第二层map就是新的每一条记录的map容器,用以得到每一条记录内部的数据,进行拆分,然后输出
updataOrder成员函数
c++
//更新预约记录
void OrderFile::updateOrder()
{
if (this->m_Size == 0)
{
return;
}
ofstream ofs;
ofs.open(ORDER_FILE, ios::out | ios::trunc);
for (int i = 0; i < this->m_Size; i++)
{
//双重访问,每次以key值访问value值,第一重的key值为i,第二重的key值为date、interval、roomId等
ofs << "date:" << this->m_OrderData[i]["date"] << " ";
ofs << "interval:" << this->m_OrderData[i]["interval"] << " ";
ofs << "romId:" << this->m_OrderData[i]["roomId"] << " ";
ofs << "stuId:" << this->m_OrderData[i]["stuId"] << " ";
ofs << "stuName:" << this->m_OrderData[i]["stuName"] << " ";
ofs << "stutas:" << this->m_OrderData[i]["stutas"] << " " << endl;
}
ofs.close();
}
8.3.2显示自身预约
首先,我们前面现添加几条预约记录进入文件,然后完善实现显示我的预约成员函数
c++
//查看自己预约
void Student::showMyOrder()
{
OrderFile of;//创建预约文件的对象,方便后续读取记录并显示记录
if (of.m_Size == 0)
{
cout << "无预约记录!" << endl;
system("pause");//按任意键继续
system("cls");//清屏
return;//返回上一级
}
for (int i = 0; i < of.m_Size; i++)
{
//string 转 int
//string利用.c_str()转为const char*
//利用atoi(const char*)转为int
if (this->m_id == atoi(of.m_OrderData[i]["stuId"].c_str()))//使用atoi强制转换为int类型进行比较
{
cout << "预约日期:周" << of.m_OrderData[i]["date"];
cout << "\t时间段: " << (of.m_OrderData[i]["interval"] == "1" ? "上午" : "下午");
cout << "\t机房号: " << of.m_OrderData[i]["roomId"];
string stutas = "审核状态:";
if (of.m_OrderData[i]["status"] == "1")
{
stutas += "审核中";
}
else if (of.m_OrderData[i]["status"] == "2")
{
stutas += "预约成功";
}
else if (of.m_OrderData[i]["status"] == "-1")
{
stutas += "预约失败,审核未通过";
}
else
{
stutas += "预约已取消";
}
cout << "\t" << stutas << endl;
}
}
system("pause");
system("cls");
}
8.3.3显示所有预约
在显示所有预约成员函数处,实现函数
c++
//查看所有预约
void Student::showAllOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "预约记录未空!暂未有预约" << endl;
system("pause");
system("cle");
return;
}
//文件不为空,打开文件读取数据
for (int i = 0; i < of.m_Size; i++)
{
cout << "预约日期:周" << of.m_OrderData[i]["date"];
cout << "\t预约时段:" << (of.m_OrderData[i]["interval"] == "1" ? "上午" : "下午");
cout << "\t机房号:" << of.m_OrderData[i]["roomId"];
cout << "\t学号:" << of.m_OrderData[i]["stuId"];
cout << "\t姓名:" << of.m_OrderData[i]["stuName"];
string status = "审核状态:";
if (of.m_OrderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_OrderData[i]["status"] == "2")
{
status += "预约成功";
}
else if (of.m_OrderData[i]["status"] == "-1")
{
status += "预约失败,审核未通过";
}
else
{
status += "预约已取消";
}
cout << "\t" << status << endl;
}
system("pause");
system("cls");
}
8.4取消预约
完善并实现成员函数取消预约
c++
//取消预约
void Student::cancelOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "系统中暂无预约!" << endl;
system("pause");
system("cls");
return;
}
cout << "审核中或预约成功的记录是可以取消的!请输入取消的记录" << endl;
vector<int>v;//存放在最大容器中的下标编号
int index = 1;//记录本人的审核中或预约成功的,筛选出来的预约条数,用以计数
for (int i = 0; i < of.m_Size; i++)
{
//先判断记录是自身的
if (this->m_id == atoi(of.m_OrderData[i]["stuId"].c_str()))
{
//再筛选状态
if (of.m_OrderData[i]["status"] == "1" || of.m_OrderData[i]["status"] == "2")
{
v.push_back(i);//此时的order.txt文件中的第i条数据是满足条件的,是本人的预约中或预约通过的,可以取消的数据
//先记录下标,届时可以直接修改本下标的status为取消预约
cout << index++ << "、";
cout << "预约日期:周" << of.m_OrderData[i]["date"];
cout << "\t预约时段" << (of.m_OrderData[i]["interval"] == "1" ? "上午" : "下午");
cout << "\t预约机房号:" << of.m_OrderData[i]["roomId"];
string status = "审核状态:";
if (of.m_OrderData[i]["status"] == "1")
{
status += "审核中";
}
else
{
status += "预约成功";
}
cout << "\t" << status << endl;
}
}
}
//已经筛选出自己的满足条件可以取消预约的记录,开始取消
cout << "请输入需要取消哪条预约,0表示返回:" << endl;
int select = 0;
while (true)
{
cin >> select;
if (select >= 0 && select <= v.size())
{
if (select == 0)
{
break;//退出循环
}
else
{
//预约记录文件中的位置下标为v容器中的对应位置记录的下标
of.m_OrderData[v[select - 1]]["status"] = "0";
of.updateOrder();//更新记录,重新写入文件
cout << "取消预约成功!" << endl;
break;
}
}
cout << "输入有误,请重新输入!" << endl;
}
system("pause");
system("cls");
}
9、教师模块
9.1教师登录和注销
9.1.1构造函数
在teacher类构造函数中,初始化教师信息
c++
//有参构造
Teacher::Teacher(int id, string name, string passWord)
{
//初始化教师属性
this->m_EmpId = id;
this->m_Name = name;
this->m_PassWord = passWord;
}
9.1.2教师子菜单
在机房预约系统.cpp文件中,当用户登录的角色是老师时,添加教师菜单接口。教师的功能包含:查看所有预约、审核预约、退出登录。添加全局函数void TeacherMenu(Person*&manager)
c++
//教师子菜单
void TeacherMenu(Identity*& teacher)
{
while (true)
{
teacher->operMenu();//调用子菜单显示
Teacher *tea = (Teacher*)teacher;//将对象转换为教师,方便调用子类特有的成员函数
cout << "请输入操作选项:" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
cout << "查看所有预约" << endl;
tea->showApply();
}
else if (select == 2)
{
cout << "审核预约" << endl;
tea->validApply();
}
else
{
delete teacher;
cout << "退出登录成功!欢迎下次使用!" << endl;
system("pause");
system("cls");
return;
}
}
}
9.2查看所有预约
该功能与学生身份查看所有预约的功能相似,用于显示所有预约记录
c++
//查看所有预约
void Teacher::showApply()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "系统暂未有预约记录!" << endl;
system("pause");
system("cls");
return;
}
//文件不为空,显示预约信息
for (int i = 0; i < of.m_Size; i++)
{
cout << i + 1 << "、";
cout << "学号:" << of.m_OrderData[i]["stuId"];
cout << "\t姓名:" << of.m_OrderData[i]["stuName"];
cout << "\t预约时间:周" << of.m_OrderData[i]["date"];
cout << "\t预约时段:" << (of.m_OrderData[i]["interval"] == "1" ? "上午" : "下午");
cout << "\t预约机房号:" << of.m_OrderData[i]["roomId"];
string status = "审核状态:";
if (of.m_OrderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_OrderData[i]["status"] == "2")
{
status += "预约成功";
}
else if (of.m_OrderData[i]["status"] == "0")
{
status += "取消预约";
}
else//-1
{
status += "预约失败,审核未通过";
}
cout << "\t" << status << endl;
}
system("pause");
system("cls");
}
9.3审核预约
老师审核学生的预约,依据实际情况预约,完善实现成员函数审核预约
c++
//审核预约
void Teacher::validApply()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "系统暂无记录!" << endl;
system("pause");
system("cls");
return;
}
vector<int>v;
int index = 1;
cout << "待审核预约记录如下:" << endl;
for (int i = 0; i < of.m_Size; i++)
{
if (of.m_OrderData[i]["status"] == "1")
{
v.push_back(i);//将满足条件的下标存入容器v中,方便后续操作。
cout << index++ << "、";
cout << "学号:" << of.m_OrderData[i]["stuId"];
cout << "\t姓名:" << of.m_OrderData[i]["stuName"];
cout << "\t预约时间:周" << of.m_OrderData[i]["date"];
cout << "\t时间段:" << (of.m_OrderData[i]["interval"] == "1" ? "上午" : "下午");
cout << "\t机房号:" << of.m_OrderData[i]["roomId"];
string status = "审核状态:";
if (of.m_OrderData[i]["status"] == "1")
{
status += "审核中";
}
else
{
status += "已审核/已取消";
}
cout << "\t" << status << endl;
}
}
cout << "请输入需要处理的预约,0表示返回:" << endl;
int select = 0;//审核哪一条记录
int ret = 0;//审核结果的记录
while (true)
{
cin >> select;
if (select >= 0 && select <= v.size())
{
if (select == 0)
{
break;
}
else
{
cout << "请输入审核结果:" << endl;
cout << "1、通过" << endl;
cout << "2、不通过" << endl;
cin >> ret;
if (ret == 1)
{
//通过
of.m_OrderData[v[select - 1]]["status"] = "2";
}
else
{
//不通过
of.m_OrderData[v[select - 1]]["status"] = "-1";
}
of.updateOrder();//更新预约记录
cout << "审核结束!" << endl;
break;
}
}
cout << "输入有误,请重新输入!" << endl;
}
system("pause");
system("cls");
}
exe运行文件在项目文件的debug文件夹内部,双击,会运行程序的main()函数