案例 —— 机房预约系统

机房预约系统

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.horderFile.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()函数

相关推荐
代码探秘者1 小时前
【Java】final、finally、finalize 区别
java·开发语言
yeflx1 小时前
C++纯虚接口
开发语言·c++
代码探秘者2 小时前
【Java】浅拷贝 VS 深拷贝:核心差异 + 实现方式 + 避坑指南
java·开发语言
永远睡不够的入2 小时前
C++list详解
c++·windows·list
Joker Zxc2 小时前
【前端基础(Javascript部分)】5、JavaScript的循环语句
开发语言·前端·javascript
不会写DN2 小时前
Golang中实时推送的功臣 - WebSocket
开发语言·后端·golang
仰泳的熊猫2 小时前
题目2268:蓝桥杯2016年第七届真题-密码脱落
数据结构·c++·算法·蓝桥杯
星辰_mya2 小时前
无锁编程:并发的“珠穆朗玛峰”与 F1 的“无缝换挡”
java·开发语言·面试
温柔一只鬼.2 小时前
Java GUI 制作 贪吃蛇小游戏
java·开发语言