#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(&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 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(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 <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<StudentInquiry(studentNo); (*exam)->dspName(20); if (item == nullptr) { cout << setw(20) << "未找到数据" << endl; } else { item->dsp(0); cout << setw(6)<<(*exam)->getStuRanking(*item)<> tmp; goBack(); }