commit 52dd9b6adf14e9c38473f0a2368162bcdb61627a Author: smh Date: Sat Sep 2 15:36:45 2023 +0800 hello world diff --git a/Exam.cpp b/Exam.cpp new file mode 100644 index 0000000..d2b3b77 --- /dev/null +++ b/Exam.cpp @@ -0,0 +1,134 @@ +#pragma warning(disable:4996) +#include"Exam.h" +using namespace std; + +Exam::Exam(Examsave* insave) { + this->save = *insave; + studentnum = insave->studentnum; + strcpy(name, insave->name); + strcpy(filename, insave->filename); + ifstream ibin(filename, ios::in, ios::binary); + Item tmp; + for (int i = 0; i < studentnum; i++) { + ibin.read((char*)&tmp, sizeof(Item)); + items.push_back(tmp); + } + ibin.close(); + if (items.size() > 0) { + sort(items.begin(), items.end()); + reverse(items.begin(), items.end()); + } +} +Exam::Exam(char inname[]) { + strcpy(name, inname); + studentnum = 0; + ifstream tmp(inname, ios::in, ios::binary); + if (tmp.good()) { + string nname; + nname += inname; + for (auto i = 1; i < 100; i++) { + nname += to_string(i); + ifstream tmp(nname, ios::in, ios::binary); + if (!tmp.good()) { + break; + } + } + strcpy(filename, nname.c_str()); + } + else { + strcpy(filename, inname); + } +} +void Exam::addItem(long long int studentNo, double score[9]) { + rmvItem(studentNo); + Item tmp(studentNo, score); + items.push_back(tmp); + sort(items.begin(), items.end()); + reverse(items.begin(), items.end()); + studentnum++; +} +void Exam::addItem(const Item& item) { + rmvItem(item.getStuNo()); + items.push_back(item); + sort(items.begin(), items.end()); + reverse(items.begin(), items.end()); + studentnum++; +} +void Exam::saveAll(ofstream& examsout) { + strcpy(save.filename, filename); + strcpy(save.name, name); + studentnum = items.size(); + save.studentnum = studentnum; + ofstream obin(filename, ios::out, ios::binary); + Item tmp; + for (auto i = items.begin(); i < items.end(); i++) { + tmp = *i; + obin.write((char*)&tmp, sizeof(Item)); + } + obin.close(); + examsout.write((char*)&this->save, sizeof(Examsave)); +} +void Exam::dspHeader() { + cout << setw(20) << "名称" << setw(15) << "学生数" << endl; +} +void Exam::dsp() const { + cout << setw(20) << name << setw(15) << studentnum << endl; +} +void Exam::dspName() const { + cout << name; +} +void Exam::dspName(int w) const { + cout << setw(w) << name; +} +void Exam::dspItems() const { + for (auto i = items.begin(); i < items.end(); i++) { + i->dsp(); + cout << setw(6) << distance(items.begin(), i) + 1 << endl; + } +} +void Exam::toCsvItems(ofstream& csv) const { + for (auto i = items.begin(); i < items.end(); i++) { + i->toCsv(csv); + csv << distance(items.begin(), i) + 1 << endl; + } +} +bool Exam::itemExists(long long int studentNo) const { + for (auto i = items.begin(); i < items.end(); i++) { + if (i->getStuNo()== studentNo) { + return true; + } + } + return false; +} +bool Exam::rmvItem(long long int studentNo) { + for (auto i = items.begin(); i < items.end(); i++) { + if (i->getStuNo() == studentNo) { + items.erase(i); + studentnum--; + return true; + } + } + return false; +} +void Exam::changeName(char name[]) { + strcpy(this->name, name); +} +const Item* Exam::StudentInquiry(long long int studentNo) const{ + for (auto item = items.begin(); item < items.end(); item++) { + if (item->getStuNo() == studentNo) { + return &(*item); + } + } + return nullptr; +} +int Exam::getStuRanking(const Item& item) { + for (auto i = items.begin(); i < items.end(); i++) { + if (i->stuNoEqual(item)) { + return distance(items.begin(), i) + 1; + } + } + return -1; +} +void Exam::rm() const { + remove(filename); +} diff --git a/Exam.h b/Exam.h new file mode 100644 index 0000000..0328eea --- /dev/null +++ b/Exam.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include"Item.h" +using namespace std; + +struct Examsave { + int studentnum; + char name[100]; + char filename[100]; +}; +class Exam { + +public: + Exam(Examsave* insave); + Exam(char inname[]); + + void saveAll(ofstream& examsout); + void addItem(long long int studentNo, double score[9]); + void addItem(const Item& item); + bool rmvItem(long long int studentNo); + static void dspHeader(); + void dsp() const; + void dspName() const; + void dspName(int w) const; + void dspItems() const; + void toCsvItems(ofstream& csv) const; + bool itemExists(long long int studentNo) const; + void changeName(char name[]); + const Item* StudentInquiry(long long int studentNo) const; + int getStuRanking(const Item& item); + void rm() const; + + virtual ~Exam(){}; +private: + vector items; + struct Examsave save; + int studentnum; + char name[100]; + char filename[100]; + + +}; \ No newline at end of file diff --git a/Item.cpp b/Item.cpp new file mode 100644 index 0000000..83cabfe --- /dev/null +++ b/Item.cpp @@ -0,0 +1,122 @@ +#include"Item.h" +#include"Student.h" +#include"Manager.h" +using namespace std; +extern Manager mainManager; +Item::Item(long long int studentNo, double inscore[]) { + sum = 0; + for (int i = 0; i < 9; i++) { + score[i] = inscore[i]; + sum = sum + score[i]; + } + this->studentNo = studentNo; +} +Item::Item() { + studentNo = -1; +} +bool Item::operator<(const Item& i) const { + if (this->sum < i.sum) { + return true; + } + else if (this->sum > i.sum) { + return false; + } + else if (this->studentNo < i.sum) { + return true; + } + else { + return false; + } +} +bool Item::operator>(const Item& i) const { + if (this->sum < i.sum) { + return false; + } + else if (this->sum > i.sum) { + return true; + } + else if (this->studentNo < i.sum) { + return false; + } + else { + return true; + } +} +long long int Item::getStuNo() const { + return studentNo; +} +bool Item::stuNoEqual(const Item& i) const { + if (this->studentNo == i.studentNo) { + return true; + } + else { + return false; + } +} +void Item::dspHeader() { + Student::dspHeader(); + cout << setw(5) << "数学" << setw(5) << "语文" << setw(5) << "英语" << setw(5) << "物理" << setw(5) << "化学" << setw(5) << "生物" << setw(5) << "历史" << setw(5) << "政治" << setw(5) << "地理" << setw(6) << "总分"; +} +void Item::dspHeader(int w) { + cout << setw(5) << "数学" << setw(5) << "语文" << setw(5) << "英语" << setw(5) << "物理" << setw(5) << "化学" << setw(5) << "生物" << setw(5) << "历史" << setw(5) << "政治" << setw(5) << "地理" << setw(6) << "总分"; +} +void Item::dsp() const { + Student* stup = mainManager.searchByNo(this->studentNo); + Student stu; + if (stup == nullptr) { + stu = Student(this->studentNo); + } + else { + stu = *stup; + } + + stu.dsp(); + cout << setw(5) << score[0] << setw(5) << score[1] << setw(5) << score[2] << setw(5) << score[3] << setw(5) << score[4] << setw(5) << score[5] << setw(5) << score[6] << setw(5) << score[7] << setw(5) << score[8] << setw(6) << sum; +} +void Item::dsp(int w) const { + cout << setw(5) << score[0] << setw(5) << score[1] << setw(5) << score[2] << setw(5) << score[3] << setw(5) << score[4] << setw(5) << score[5] << setw(5) << score[6] << setw(5) << score[7] << setw(5) << score[8] << setw(6) << sum; +} +void Item::toCsvHeader(ofstream& csv) { + Student::toCsvHeader(csv); + csv << "数学," << "语文," << "英语," << "物理," << "化学," << "生物," << "历史," << "政治," << "地理," << "总分,"; +} +void Item::toCsv(ofstream& csv) const { + Student* stup = mainManager.searchByNo(this->studentNo); + Student stu; + if (stup == nullptr) { + stu = Student(this->studentNo); + } + else { + stu = *stup; + } + stu.toCsv(csv); + csv << score[0] << "," << score[1] << "," << score[2] << "," << score[3] << "," << score[4] << "," << score[5] << "," << score[6] << "," << score[7] << "," << score[8] << "," << sum << ","; +} +Item::Item(ifstream& csv, int stuNoColumn,int scoreColumn[]) { + string line, tmp; + vector tmpvector; + sum = 0; + if (!getline(csv,line)) { + studentNo = -1; + return; + } + stringstream linestream(line); + while (getline(linestream, tmp, ',')) { + tmpvector.push_back(tmp); + }; + try { + studentNo = stoi(tmpvector.at(stuNoColumn-1)); + } + catch (const exception& e) { + studentNo = 0; + } + for (auto i = 0; i < 9; i++) { + try { + score[i] = stoi(tmpvector.at(scoreColumn[i]-1)); + } + catch (const exception& e) { + score[i] = 0; + } + sum += score[i]; + } +} diff --git a/Item.h b/Item.h new file mode 100644 index 0000000..1e64129 --- /dev/null +++ b/Item.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +using namespace std; +class Item { +public: + Item(long long int studentNo, double inscore[]); + Item(ifstream& csv, int stuNoColumn, int scoreColumn[]); + Item(); + + bool operator>(const Item& i) const; + bool operator<(const Item& i) const; + long long int getStuNo() const; + bool stuNoEqual(const Item& i) const; + static void dspHeader(); + static void dspHeader(int w); + void dsp() const; + void dsp(int w) const; + static void toCsvHeader(ofstream& csv); + void toCsv(ofstream& csv) const; + + virtual ~Item() {} +private: + long long int studentNo; + double score[9]; + double sum; +}; \ No newline at end of file diff --git a/Manager.cpp b/Manager.cpp new file mode 100644 index 0000000..3a08e31 --- /dev/null +++ b/Manager.cpp @@ -0,0 +1,907 @@ +#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(); +} diff --git a/Manager.h b/Manager.h new file mode 100644 index 0000000..e261281 --- /dev/null +++ b/Manager.h @@ -0,0 +1,67 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include"Student.h" +#include"Exam.h" +using namespace std; +class Manager { +public: + Manager(); + + void mainLoop(); + void goBack(); + void centeredPrint(const string& content); + Student* searchByNo(long long int studentNo); + //status 0 + void welcomePage(); + //status 1 + void stuPage(); + //status 11 + void stuDspPage(); + //status 12 + void stuAddPage(); + //status 13 + void stuSearchPage(); + //status 14 + void stuEdtRmvPage(); + //status 15 + void stuExportPage(); + //status 16 + void stuImportPage(); + //status 2 + void examPage(); + //status 21 + void examAddPage(); + //status 22 + void examChoosePage(); + //status 23 + void examSubPage(); + //status 231 + void examViewPage(); + //status 232 + void examExportPage(); + //status 233 + void examAddRowPage(); + //status 234 + void examDelRowPage(); + //status 235 + void examNamePage(); + //status 236 + void examImportPage(); + //status 237 + void examRmvPage(); + //status 3 + void stuPfmPage(); + + virtual ~Manager(); +private: + int status = 0; + int ExamNum = 0, StudentNum = 0; + vector Students; + vector> Exams; + vector>::iterator currentExam = Exams.begin(); +}; \ No newline at end of file diff --git a/Student.cpp b/Student.cpp new file mode 100644 index 0000000..6eb1c9a --- /dev/null +++ b/Student.cpp @@ -0,0 +1,124 @@ +#include"Student.h" +#include"Manager.h" +#pragma warning(disable:4996) +using namespace std; +extern Manager mainManager; +Student::Student(int year, int selectionNo, int classNo, char name[]) :year(year), selectionNo(selectionNo), classNo(classNo), serialNo(serialNo) { + strcpy_s(this->name, name); + studentNo = infoToNo(year, selectionNo, classNo); + serialNo = studentNo % 100; +} +Student::Student(long long int studentNo) { + this->studentNo = studentNo; + strcpy(this->name, "查无此人"); + year = 0; + selectionNo = 0; + classNo = 0; + serialNo = 0; +} +Student::Student(ifstream& csv, int yearColumn, int clsColumn, int slcColumn,int nameColumn) { + string line, tmp; + vector tmpvector; + if (!getline(csv, line)) { + studentNo = -1; + return; + } + stringstream linestream(line); + while (getline(linestream, tmp, ',')) { + tmpvector.push_back(tmp); + }; + try { + year = stoi(tmpvector.at(yearColumn - 1)); + } + catch (const exception& e) { + year = 0; + } + try { + classNo = stoi(tmpvector.at(clsColumn - 1)); + } + catch (const exception& e) { + classNo = 0; + } + try { + selectionNo = stoi(tmpvector.at(slcColumn - 1)); + } + catch (const exception& e) { + selectionNo = 0; + } + strcpy(this->name, tmpvector.at(nameColumn - 1).c_str()); + if (year != 0 && classNo != 0 && selectionNo != 0) { + studentNo = infoToNo(year, selectionNo, classNo); + serialNo = studentNo % 100; + } + else { + studentNo = 0; + serialNo = 0; + } +} +void Student::dspHeader() { + cout << setw(10) << "姓名" << setw(12) << "学号" << setw(10) << "入学年份" << setw(5) << "班级" << setw(5) << "选科"; +} +void Student::dsp() const { + cout << setw(10) << name << setw(12) << studentNo << setw(10) << year << setw(5) << classNo << setw(5) << selectionNo; +} +void Student::toCsvHeader(ofstream& csv) { + csv<< "姓名,"<< "学号,"<< "入学年份,"<< "班级," << "选科,"; +} +void Student::toCsv (ofstream& csv) const { + csv << name << ',' << studentNo << ',' << year << ',' << classNo << ',' << selectionNo << ','; +} +void Student::setInfo(int year, int selectionNo, int classNo, char name[]) { + this->year = year; + this->selectionNo = selectionNo; + this->classNo = classNo; + strcpy(this->name, name); +} +bool Student::stuNoEqual(long long int studentNo) const { + if (this->studentNo == studentNo) { + return true; + } + else { + return false; + } +} +bool Student::slcNoEqual(int selectionNo) const { + if (this->selectionNo == selectionNo) { + return true; + } + else { + return false; + } +} +bool Student::clsNoEqual(int classNo) const { + if (this->classNo == classNo) { + return true; + } + else { + return false; + } +} +bool Student::nameEqual(char name[]) const { + if (strcmp(this->name, name) == 0) { + return true; + } + else { + return false; + } +} +bool Student::yearEqual(int year) const { + if (this->year == year) { + return true; + } + else { + return false; + } +} +long long int Student::infoToNo(int year, int selectionNo, int classNo) { + long long int initNo = year * 1000000 + selectionNo * 10000 + classNo * 100 + 1; + for (auto i = initNo; i < initNo + 99; i++) { + if (mainManager.searchByNo(i) == nullptr) { + return i; + } + } + return -1; +} diff --git a/Student.h b/Student.h new file mode 100644 index 0000000..3f96775 --- /dev/null +++ b/Student.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include +#include +#include +using namespace std; + +class Student { +public: + Student(int year, int selectionNo, int classNo, char name[]); + Student(long long int studentNo); + Student(ifstream& csv, int yearColumn, int clsColumn, int slcColumn,int nameColumn); + Student(){} + + void setInfo(int year, int selectionNo, int classNo, char name[]); + bool stuNoEqual(long long int studentNo) const; + bool slcNoEqual(int selectionNo) const; + bool clsNoEqual(int classNo) const; + bool yearEqual(int year) const; + bool nameEqual(char name[]) const; + static void dspHeader(); + void dsp() const; + static void toCsvHeader(ofstream& csv); + void toCsv(ofstream& csv) const; + static long long int infoToNo(int year,int selectionNo, int classNo); + + virtual ~Student(){}; +private: + long long int studentNo; + char name[100]; + int year; + int selectionNo; + int classNo; + int serialNo; +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..118fb42 --- /dev/null +++ b/main.cpp @@ -0,0 +1,8 @@ +#include"Exam.h" +#include"Student.h" +#include"Manager.h" +Manager mainManager; +using namespace std; +int main() { + mainManager.mainLoop(); +} \ No newline at end of file