cppHomework/Manager.cpp

908 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Manager.h"
#include"Exceptions.h"
#pragma warning(disable:4996)
Manager::Manager() {
centeredPrint("##########################################");
centeredPrint("## 学生成绩管理系统 ##");
centeredPrint("##########################################");
cout << endl;
centeredPrint("加载中...");
ifstream numsin("nums.bin", ios::in, ios::binary);
if (!numsin.good()) {
ExamNum = 0;
StudentNum = 0;
numsin.close();
return;
}
numsin.read((char*)&StudentNum, sizeof(int));
numsin.read((char*)&ExamNum, sizeof(int));
numsin.close();
ifstream studentsin("students.bin", ios::in, ios::binary);
Student tmpstu;
for (int i = 0; i < StudentNum; i++) {
studentsin.read((char*)&tmpstu, sizeof(Student));
Students.push_back(tmpstu);
}
studentsin.close();
ifstream examsin("examsaves.bin", ios::in, ios::binary);
Examsave tmpexam;
for (int i = 0; i < ExamNum; i++) {
examsin.read((char*)&tmpexam, sizeof(Examsave));
auto sp1 = make_shared<Exam>(&tmpexam);
Exams.push_back(sp1);
}
examsin.close();
cout << endl;
centeredPrint("欢迎使用!");
}
Manager::~Manager() {
centeredPrint("保存中...");
ofstream examsout("examsaves.bin", ios::out, ios::binary);
for (auto i = Exams.begin(); i < Exams.end(); i++) {
(*i)->saveAll(examsout);
}
ExamNum = Exams.size();
examsout.close();
ofstream studentsout("students.bin", ios::out, ios::binary);
for (auto i = Students.begin(); i < Students.end(); i++) {
studentsout.write((char*)&(*i), sizeof(Student));
}
StudentNum = Students.size();
studentsout.close();
ofstream numsout("nums.bin", ios::out, ios::binary);
numsout.write((char*)&StudentNum, sizeof(int));
numsout.write((char*)&ExamNum, sizeof(int));
numsout.close();
centeredPrint("已保存!");
}
void Manager::mainLoop() {
while (1) {
try {
switch (status) {
case 0:
welcomePage();
break;
case 1:
stuPage();
break;
case 11:
stuDspPage();
break;
case 12:
stuAddPage();
break;
case 13:
stuSearchPage();
break;
case 14:
stuEdtRmvPage();
break;
case 15:
stuExportPage();
break;
case 16:
stuImportPage();
break;
case 2:
examPage();
break;
case 21:
examAddPage();
break;
case 22:
examChoosePage();
break;
case 23:
examSubPage();
break;
case 231:
examViewPage();
break;
case 232:
examExportPage();
break;
case 233:
examAddRowPage();
break;
case 234:
examDelRowPage();
break;
case 235:
examNamePage();
break;
case 236:
examImportPage();
break;
case 237:
examRmvPage();
break;
case 3:
stuPfmPage();
break;
}
system("cls");
if (status == -1)
break;
}
catch (const InputError& e) {
system("cls");
cerr << e.what() << endl;
cin.clear();
cin.ignore(1024,'\n');
goBack();
}
catch (const FileError& e) {
system("cls");
cerr << e.what() << endl;
goBack();
}
catch (const IndexError& e) {
system("cls");
cerr << e.what() << endl;
goBack();
}
}
}
void Manager::goBack() {
status /= 10;
}
void Manager::centeredPrint(const string& content) {
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo(hOutput, &bInfo);
int dwSizeX = bInfo.dwSize.X, dwSizeY = bInfo.dwSize.Y;
int cursorX = bInfo.dwCursorPosition.X, cursorY = bInfo.dwCursorPosition.Y;
int len = content.length();
COORD pos;
pos.X = (dwSizeX - len) / 2;
pos.Y = cursorY;
SetConsoleCursorPosition(hOutput, pos);
cout << content << endl;
}
Student* Manager::searchByNo(long long int studentNo) {
for (auto i = Students.begin(); i < Students.end(); i++) {
if (i->stuNoEqual(studentNo)) {
return &(*i);
}
}
return nullptr;
}
//status 0
void Manager::welcomePage() {
char choice = '0';
cout << "主菜单" << endl;
cout << "请选择" << endl;
cout << "1: 学生信息管理" << endl;
cout << "2: 考试信息" << endl;
cout << "3: 学生成绩查询" << endl;
cout << "q: 退出" << endl;
cin >> choice;
switch (choice) {
case '1':
status = 1;
break;
case '2':
status = 2;
break;
case '3':
status = 3;
break;
case 'q':
case 'Q':
status = -1;
break;
}
}
//status 1
void Manager::stuPage() {
char choice = '0';
cout << "主菜单-学生" << endl;
cout << "请选择" << endl;
cout << "1: 全部学生信息" << endl;
cout << "2: 添加新学生" << endl;
cout << "3: 学生信息搜索" << endl;
cout << "4: 编辑/删除已有学生" << endl;
cout << "5: 将全部学生信息导出到CSV" << endl;
cout << "6: 从CSV导入学生信息" << endl;
cout << "b: 返回" << endl;
cin >> choice;
switch (choice) {
case '1':
status = 11;
break;
case '2':
status = 12;
break;
case '3':
status = 13;
break;
case '4':
status = 14;
break;
case '5':
status = 15;
break;
case '6':
status = 16;
break;
case 'b':
case 'B':
goBack();
}
}
//status 11
void Manager::stuDspPage() {
cout << "主菜单-学生-信息查看" << endl;
cout << setw(6) << "编号";
Student::dspHeader();
cout << endl;
int count = 1;
for (auto student = Students.begin(); student < Students.end(); student++) {
cout << setw(6) << count++;
student->dsp();
cout << endl;
}
string tmp;
cout << endl << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 12
void Manager::stuAddPage() {
char choice = '0';
cout << "主菜单-学生-添加" << endl;
int year;
int selectionNo;
int classNo;
char name[100];
cout << "姓名:" << endl;
do {
cin.getline(name, 100);
} while (name[0] == '\0');
cout << "入学年份:" << endl;
cin >> year;
cout << "选科组合:" << endl;
cin >> selectionNo;
cout << "班级:" << endl;
cin >> classNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
Students.push_back(Student(year, selectionNo, classNo, name));
cout << "已添加!" << endl;
string tmp;
cout << endl << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 13
void Manager::stuSearchPage() {
char choice = '0';
cout << "主菜单-学生-搜索" << endl;
cout << "请选择:" << endl;
cout << "1: 按学号搜索" << endl;
cout << "2: 按姓名搜索" << endl;
cout << "3: 按班级搜索" << endl;
cout << "4: 按选科组合搜索" << endl;
cout << "5: 按入学年份搜索" << endl;
cout << "b: 返回" << endl;
cin >> choice;
vector<Student> result;
int enrollmentYear;
switch (choice) {
case '1':
long long int inputNo;
cout << "请输入学号:";
cin >> inputNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->stuNoEqual(inputNo)) {
result.push_back(*stu);
}
}
break;
case '2':
char inputName[100];
cout << "请输入学生姓名:";
do {
cin.getline(inputName, 100);
} while (inputName[0] == '\0');
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->nameEqual(inputName)) {
result.push_back(*stu);
}
}
break;
case '3':
int inputClassNo;
cout << "请输入入学年份:";
cin >> enrollmentYear;
cout << "请输入班级:";
cin >> inputClassNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->clsNoEqual(inputClassNo) && stu->yearEqual(enrollmentYear)) {
result.push_back(*stu);
}
}
break;
case '4':
int inputSelectionNo;
cout << "请输入入学年份:";
cin >> enrollmentYear;
cout << "请输入选科组合:";
cin >> inputSelectionNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->slcNoEqual(inputSelectionNo) && stu->yearEqual(enrollmentYear)) {
result.push_back(*stu);
}
}
break;
case '5':
cout << "请输入入学年份:";
cin >> enrollmentYear;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->yearEqual(enrollmentYear)) {
result.push_back(*stu);
}
}
break;
case 'b':
case 'B':
goBack();
}
if (status != 1) {
cout << setw(6) << "编号";
Student::dspHeader();
cout << endl;
int count = 1;
for (auto student = result.begin(); student < result.end(); student++) {
cout << setw(6) << count++;
student->dsp();
cout << endl;
}
cout << endl;
if (result.size() == 0) {
cout << "未找到符合条件的学生" << endl;
}
cout << "b: 返回" << endl;
string tmp;
cin >> tmp;
goBack();
}
}
//status 14
void Manager::stuEdtRmvPage() {
int inputNo;
string tmp;
cout << "主菜单-学生-编辑/删除" << endl;
cout << "请输入学号:";
cin >> inputNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
auto it = Students.end();
for (auto stu = Students.begin(); stu < Students.end(); stu++) {
if (stu->stuNoEqual(inputNo)) {
it = stu;
}
}
if (it == Students.end()) {
cout << "查无此人" << endl;
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
else {
char choice;
cout << "1: 编辑学生信息" << endl;
cout << "2: 删除" << endl;
cin >> choice;
Student::dspHeader();
cout << endl;
it->dsp();
cout << endl;
if (choice == '1') {
int year;
int selectionNo;
int classNo;
char name[100];
cout << "姓名:" << endl;
do {
cin.getline(name, 100);
} while (name[0] == '\0');
cout << "入学年份:" << endl;
cin >> year;
cout << "选科组合:" << endl;
cin >> selectionNo;
cout << "班级:" << endl;
cin >> classNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
it->setInfo(year, selectionNo, classNo, name);
cout << "已修改" << endl;
}
else if (choice == '2') {
cout << "删除上述学生?(Y(是)/N(否))" << endl;
char yorn;
cin >> yorn;
if (yorn == 'y' || yorn == 'Y') {
Students.erase(it);
}
cout << "已删除" << endl;
}
cout << "b: 返回" << endl;
string tmp;
cin >> tmp;
goBack();
}
}
//status 15
void::Manager::stuExportPage() {
cout << "主菜单-学生-导出" << endl;
string csvName;
cout << "请输入导出文件名:" << endl;
do {
getline(cin, csvName);
} while (csvName == "");
csvName = csvName + ".csv";
ofstream csv(csvName);
if (!csv.good()) {
throw FileError("文件创建失败!");
}
Student::toCsvHeader(csv);
csv << '\n';
for (auto student = Students.begin(); student < Students.end(); student++) {
student->toCsv(csv);
csv << '\n';
}
string tmp;
cout << "导出成功" << endl;
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 16
void::Manager::stuImportPage() {
string fileName;
string tmp;
bool eof = false;
int firstRow=1;
int clsColumn, slcColumn, yearColumn,nameColumn;
cout << "主菜单-学生-导入" << endl;
cout << "请输入文件名称或路径,注意包含扩展名" << endl;
cin >> fileName;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
ifstream csvFile(fileName);
if (!csvFile.good()) {
throw FileError("文件打开失败!");
}
cout << "请输入有效数据开始的行数: " << endl;
cin >> firstRow;
cout << "请输入学生姓名所在的列数: " << endl;
cin >> nameColumn;
cout << "请输入入学年份所在的列数: " << endl;
cin >> yearColumn;
cout << "请输入班号所在的列数: " << endl;
cin >> clsColumn;
cout << "请输入选科组合所在的列数: " << endl;
cin >> slcColumn;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (int i = 1; i < firstRow; i++) {
getline(csvFile, tmp);
}
while (!eof) {
Student tmpStu(csvFile, yearColumn, clsColumn, slcColumn, nameColumn);
if (tmpStu.stuNoEqual(-1)) {
eof = true;
}
else if (tmpStu.stuNoEqual(0)) {
continue;
}
else {
Students.push_back(tmpStu);
}
}
cout << "已导入" << endl;
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 2
void Manager::examPage() {
char choice = '0';
cout << "主菜单-考试" << endl;
cout << setw(6) << "编号";
Exam::dspHeader();
for (auto exam = Exams.begin(); exam < Exams.end(); exam++) {
cout << setw(4) << distance(Exams.begin(), exam) + 1;
(*exam)->dsp();
}
cout << endl;
cout << "请选择" << endl;
cout << "1: 添加考试" << endl;
cout << "2: 选择考试" << endl;
cout << "b: 返回" << endl;
cin >> choice;
switch (choice) {
case '1':
status = 21;
break;
case '2':
status = 22;
break;
case 'b':
case 'B':
goBack();
break;
}
}
//status 21
void Manager::examAddPage() {
cout << "主菜单-考试-添加" << endl;
cout << "名称:" << endl;
char name[100];
do {
cin.getline(name, 100);
} while (name[0] == '\0');
auto p = make_shared<Exam>(name);
Exams.push_back(p);
cout << "添加成功!" << endl;
cout << "b: 返回" << endl;
string tmp;
cin >> tmp;
goBack();
}
//status 22
void Manager::examChoosePage() {
int examNo;
string tmp;
cout << "主菜单-考试-选择" << endl;
cout << setw(6) << "编号";
Exam::dspHeader();
for (auto exam = Exams.begin(); exam < Exams.end(); exam++) {
cout << setw(6) << distance(Exams.begin(), exam) + 1;
(*exam)->dsp();
}
cout << endl;
cout << "编号:" << endl;
cin >> examNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
examNo--;
if (examNo >= 0 && examNo < Exams.size()) {
currentExam = Exams.begin() + examNo;
status = 23;
}
else {
throw IndexError("编号无效!");
}
}
//status 23
void Manager::examSubPage() {
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << endl;
cout << "请选择:" << endl;
cout << "1: 查看全部成绩" << endl;
cout << "2: 导出为CSV" << endl;
cout << "3: 新增成绩" << endl;
cout << "4: 删除成绩" << endl;
cout << "5: 修改考试名称" << endl;
cout << "6: 从CSV导入" << endl;
cout << "7: 删除此考试及其所有成绩信息" << endl;
cout << "b: 返回" << endl;
char choice = '0';
cin >> choice;
switch (choice) {
case '1':
status = 231;
break;
case '2':
status = 232;
break;
case '3':
status = 233;
break;
case '4':
status = 234;
break;
case '5':
status = 235;
break;
case '6':
status = 236;
break;
case '7':
status = 237;
break;
case 'b':
case 'B':
goBack();
}
}
//status 231
void Manager::examViewPage() {
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-查看" << endl;
Item::dspHeader();
cout <<setw(6)<< "名次" << endl;
(*currentExam)->dspItems();
string tmp;
cout << endl << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 232
void Manager::examExportPage() {
string csvName;
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-导出" << endl;
cout << "请输入导出文件名:" << endl;
do {
getline(cin, csvName);
} while (csvName == "");
csvName = csvName + ".csv";
ofstream csv(csvName);
if (!csv.good()) {
throw FileError("文件创建失败!");
}
Item::toCsvHeader(csv);
csv << "名次" << endl;
(*currentExam)->toCsvItems(csv);
csv.close();
cout << "导出完成" << endl;
string tmp;
cout << endl << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 233
void Manager::examAddRowPage() {
long long int studentNo;
double score[9];
char yorn;
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-新增成绩" << endl;
cout << "学号:" << endl;
cin >> studentNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
if ((*currentExam)->itemExists(studentNo)) {
cout << "学号" << studentNo << "的成绩已存在, 是否覆盖? (Y(是)/N(否))" << endl;
cin >> yorn;
if (yorn != 'Y' && yorn != 'y') {
status = 23;
return;
}
}
cout << "数学:" << endl;
cin >> score[0];
cout << "语文:" << endl;
cin >> score[1];
cout << "英语:" << endl;
cin >> score[2];
cout << "物理:" << endl;
cin >> score[3];
cout << "化学:" << endl;
cin >> score[4];
cout << "生物:" << endl;
cin >> score[5];
cout << "历史:" << endl;
cin >> score[6];
cout << "政治:" << endl;
cin >> score[7];
cout << "地理:" << endl;
cin >> score[8];
if (!cin.good()) {
throw InputError("输入字符非法!");
}
(*currentExam)->addItem(studentNo, score);
cout << "已添加" << endl;
string tmp;
cout << endl << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 234
void Manager::examDelRowPage() {
char yorn;
long long int studentNo;
string tmp;
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-删除成绩" << endl;
cout << "学号:" << endl;
cin >> studentNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
cout << "确认删除(Y(是)/N(否))" << endl;
cin >> yorn;
if (yorn == 'Y' || yorn == 'y') {
yorn=(*currentExam)->rmvItem(studentNo);
if (yorn) {
cout << "已删除" << endl;
}
else {
cout << "未找到" << endl;
}
}
else {
cout << "已取消" << endl;
}
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 235
void Manager::examNamePage() {
string tmp;
char name[100];
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-修改名称" << endl;
cout << "新名称:" << endl;
do {
cin.getline(name, 100);
} while (name[0] == '\0');
(*currentExam)->changeName(name);
cout << "已修改" << endl;
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 236
void Manager::examImportPage() {
string tmp;
string fileName;
int firstRow;
int stuNoColumn;
int scoreColumn[9];
bool eof=false;
char name[100];
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-导入" << endl;
cout << "注意若此考试中已存在相同学号学生的成绩数据从CSV导入的数据会将其覆盖" << endl;
cout << "请输入文件名称或路径,注意包含扩展名" << endl;
cin >> fileName;
ifstream csvFile(fileName);
if (!csvFile.good()) {
throw FileError("文件打开失败!");
}
cout << "请输入有效数据开始的行数: " << endl;
cin >> firstRow;
cout << "请输入学号所在的列数:" << endl;
cin >> stuNoColumn;
cout << "请输入数学、语文、英语、物理、化学、生物、历史、政治、地理成绩所在的列数,以空格分隔" << endl;
cin >> scoreColumn[0] >> scoreColumn[1] >> scoreColumn[2] >> scoreColumn[3] >> scoreColumn[4] >> scoreColumn[5] >> scoreColumn[6] >> scoreColumn[7] >> scoreColumn[8];
if (!cin.good()) {
throw InputError("输入字符非法!");
}
for (int i = 1; i < firstRow; i++) {
getline(csvFile, tmp);
}
while (!eof) {
Item tmpItem(csvFile, stuNoColumn, scoreColumn);
if (tmpItem.getStuNo()==-1) {
eof = true;
}
else if(tmpItem.getStuNo()==0) {
continue;
}
else {
(*currentExam)->addItem(tmpItem);
}
}
cout << "已导入" << endl;
cout << "b: 返回" << endl;
cin >> tmp;
goBack();
}
//status 237
void Manager::examRmvPage() {
string tmp;
cout << "主菜单-考试-";
(*currentExam)->dspName();
cout << "-删除考试" << endl;
cout << "你确定要删除考试\"";
(*currentExam)->dspName();
cout<< "\"" << endl;
cout << "输入 \"confirm\" 以确认删除" << endl;
cin >> tmp;
if (tmp == "confirm") {
(*currentExam)->rm();
Exams.erase(currentExam);
currentExam = Exams.begin();
goBack();
goBack();
cout << "已删除" << endl;
}
else {
goBack();
cout << "已取消" << endl;
}
cout << "b: 返回" << endl;
cin >> tmp;
}
//status 3
void Manager::stuPfmPage() {
long long int studentNo;
cout << "主菜单-学生成绩查询" << endl;
cout << "学号:" << endl;
cin >> studentNo;
if (!cin.good()) {
throw InputError("输入字符非法!");
}
Student::dspHeader();
cout << endl;
if (searchByNo(studentNo) == nullptr) {
cout << setw(20) << "未找到数据" << endl;
}
else {
searchByNo(studentNo)->dsp();
}
cout << endl << endl;
cout << "历次考试成绩:" << endl<<endl;
cout << setw(20) << "考试名称";
Item::dspHeader(0);
cout << setw(6) << "名次" << endl;
for (auto exam = Exams.begin(); exam < Exams.end(); exam++) {
auto item = (*exam)->StudentInquiry(studentNo);
(*exam)->dspName(20);
if (item == nullptr) {
cout << setw(20) << "未找到数据" << endl;
}
else {
item->dsp(0);
cout << setw(6)<<(*exam)->getStuRanking(*item)<<endl;
}
}
string tmp;
cout <<endl<< "b: 返回" << endl;
cin >> tmp;
goBack();
}