studentpage.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #include "studentpage.h"
  2. #include "appevent.h"
  3. #include "cwf/sqlquerymanager.h"
  4. #include "qcombobox.h"
  5. #include "qjsonarray.h"
  6. #include "qjsonvalue.h"
  7. #include "qnamespace.h"
  8. #include "tmodel.h"
  9. #include "widgets/pagination.h"
  10. #include "widgets/studentmodel.h"
  11. #include <QCheckBox>
  12. #include <QComboBox>
  13. #include <QDialog>
  14. #include <QHeaderView>
  15. #include <QLabel>
  16. #include <QLineEdit>
  17. #include <QPainter>
  18. #include <QStatusBar>
  19. #include <QStyledItemDelegate>
  20. #include <QTableView>
  21. #include <xlsxdocument.h>
  22. #include <QFileDialog>
  23. #include <QJsonArray>
  24. #include <QMessageBox>
  25. #include <layoutbuilder.h>
  26. #include "cwf/sqlquery.h"
  27. #include <cwf/constants.h>
  28. #include <cwf/cppwebapplication.h>
  29. #include <cwf/filter.h>
  30. #include <cwf/sqldatabasestorage.h>
  31. #include "teachertr.h"
  32. static CWF::SqlDatabaseStorage storage("QSQLITE", "localhost", "data.db", "", "");
  33. class TagDelegate : public QStyledItemDelegate
  34. {
  35. public:
  36. TagDelegate(QObject *parent = nullptr)
  37. : QStyledItemDelegate(parent)
  38. {}
  39. void paint(QPainter *painter,
  40. const QStyleOptionViewItem &option,
  41. const QModelIndex &index) const override
  42. {
  43. QStyledItemDelegate::paint(painter, option, index);
  44. // 获取数据
  45. QString tagText = index.data(Qt::DisplayRole).toString();
  46. QColor color = Qt::lightGray;
  47. if (tagText == "1") {
  48. tagText = TeacherServer::Tr::tr("online");
  49. color = Qt::green;
  50. } else {
  51. tagText = TeacherServer::Tr::tr("outline");
  52. }
  53. // 设置背景色和边框
  54. painter->save();
  55. painter->setRenderHint(QPainter::Antialiasing);
  56. painter->setPen(Qt::NoPen);
  57. painter->setBrush(color); // 背景色
  58. painter->drawRoundedRect(option.rect.adjusted(2, 2, -2, -2), 5, 5); // 圆角矩形
  59. // 设置文本颜色和对齐方式
  60. painter->setPen(QColor("#0078D4")); // 文本颜色
  61. painter->setFont(QFont("Arial", 10));
  62. painter->drawText(option.rect.adjusted(5, 2, -5, -2), Qt::AlignCenter, tagText);
  63. painter->restore();
  64. }
  65. QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
  66. {
  67. // 返回标签的合适大小
  68. QString tagText = index.data(Qt::DisplayRole).toString();
  69. QFontMetrics fm(option.font);
  70. QSize size = fm.size(0, tagText);
  71. return size + QSize(10, 4); // 调整大小,以适应内容
  72. }
  73. };
  74. StudentPage::StudentPage(QWidget *parent)
  75. : QWidget{parent}
  76. {
  77. using namespace Layouting;
  78. studentView = new QTableView;
  79. pagination = new Pagination;
  80. pageSize = new QComboBox;
  81. pageSize->addItem("10", 10);
  82. pageSize->addItem("20", 20);
  83. pageSize->addItem("30", 30);
  84. pageSize->addItem("50", 50);
  85. pageSize->addItem("100", 100);
  86. studentNameLineEdit = new QLineEdit;
  87. studentSwLineEdit = new QLineEdit;
  88. examineeNumberLineEdit = new QLineEdit;
  89. checkinNumberLineEdit = new QLineEdit;
  90. examsTestLineEdit = new QLineEdit;
  91. groupNameComboBox = new QComboBox;
  92. groupNameComboBox->addItem("小学");
  93. groupNameComboBox->addItem("初中");
  94. groupNameComboBox->addItem("高中");
  95. auto studentEditor = Form{tr("name"),
  96. studentNameLineEdit,
  97. br,
  98. tr("swID"),
  99. studentSwLineEdit,
  100. br,
  101. tr("examinee number"),
  102. examineeNumberLineEdit,
  103. noMargin()}
  104. .emerge();
  105. auto studentEditorRight = Form{tr("checkin number"),
  106. checkinNumberLineEdit,
  107. br,
  108. tr("group name"),
  109. groupNameComboBox,
  110. br,
  111. tr("exams test"),
  112. examsTestLineEdit,
  113. noMargin()}
  114. .emerge();
  115. auto op = Column{PushButton{text(tr("Add")), onClicked([this]() { addStudent(); })},
  116. PushButton{text(tr("Remove")), onClicked([this]() { removeStudent(); })},
  117. PushButton{text(tr("Set as Default")), onClicked([this]() { setDefault(); })},
  118. st,
  119. PushButton{text(tr("Clear...")), onClicked([this]() { Clear(); })},
  120. PushButton{text(tr("Import...")), onClicked([this]() { importFile(); })},
  121. PushButton{text(tr("Export...")), onClicked([this]() { exportFile(); })},
  122. st,
  123. PushButton{text(tr("Save")), onClicked([this]() { save(); })}}
  124. .emerge();
  125. // examsEditor->setMinimumWidth(300);
  126. op->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
  127. auto pageWidget = Row{pagination, st, tr("pageSize"), pageSize, st};
  128. Row{Column{studentView, pageWidget, Row{studentEditor, studentEditorRight}}, op}.attachTo(this);
  129. // 创建数据模型
  130. StudentTableModel *model = new StudentTableModel;
  131. // 创建表格视图
  132. studentView->setModel(model);
  133. studentView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
  134. studentView->setSelectionBehavior(QAbstractItemView::SelectRows);
  135. studentView->setSelectionMode(QAbstractItemView::SingleSelection);
  136. studentView->setItemDelegateForColumn(StudentTableModel::STATE,
  137. new TagDelegate(this)); // 设置第0列应用委托
  138. AppEvent *appEvent = AppEvent::instance();
  139. // 连接信号和槽
  140. QObject::connect(appEvent, &AppEvent::loginUserSignal, [this](int) { updateStudentView(); });
  141. QObject::connect(appEvent, &AppEvent::loginOutUserSignal, [this](int) { updateStudentView(); });
  142. QObject::connect(pagination, &Pagination::valueChanged, [this](int) { updateStudentView(); });
  143. QObject::connect(pageSize, &QComboBox::currentTextChanged, [this](const QString &) {
  144. updateStudentView();
  145. });
  146. connect(studentView, &QTableView::clicked, this, [=](const QModelIndex &index) {
  147. StudentTableModel *model = qobject_cast<StudentTableModel *>(studentView->model());
  148. StudentTableModel::Student student = model->getCurrentStudent(index);
  149. studentNameLineEdit->setText(student.name);
  150. studentSwLineEdit->setText(student.swID);
  151. examineeNumberLineEdit->setText(student.examineeNumber);
  152. checkinNumberLineEdit->setText(student.checkinNumber);
  153. groupNameComboBox->setCurrentText(student.groupName);
  154. examsTestLineEdit->setText(student.examTest);
  155. });
  156. updateStudentView();
  157. }
  158. void StudentPage::updateStudentView()
  159. {
  160. int size = pageSize->currentData().toInt();
  161. pagination->setPageSizes(size);
  162. UserModel userModel(storage);
  163. StudentTableModel *model = qobject_cast<StudentTableModel *>(studentView->model());
  164. CWF::SqlQueryManager queryManager(storage);
  165. queryManager.select("COUNT(*) AS total", userModel.getTableName());
  166. queryManager.exec(queryManager.getQueryText());
  167. QJsonArray array = queryManager.toJson();
  168. if (!array.isEmpty()) {
  169. QJsonObject object = array[0].toObject();
  170. qint64 total = object["total"].toVariant().toLongLong();
  171. pagination->setTotal(total);
  172. }
  173. int pageNumber = pagination->currentPage();
  174. int pageSize = pagination->pageSizes();
  175. QString queryStr = QString("SELECT * FROM %1 LIMIT %2 OFFSET %3")
  176. .arg(userModel.getTableName())
  177. .arg(pageSize)
  178. .arg((pageNumber - 1) * pageSize);
  179. queryManager.exec(queryStr);
  180. model->loadJsonData(queryManager.toJson());
  181. }
  182. void StudentPage::addStudent()
  183. {
  184. UserModel userModel(storage);
  185. CWF::SqlQueryManager queryManager(storage);
  186. queryManager.insert(userModel.getTableName(), "name,swID,state,examineeNumber,maxTime");
  187. queryManager.prepare();
  188. queryManager.addBindValue("");
  189. queryManager.addBindValue("");
  190. queryManager.addBindValue("0");
  191. queryManager.addBindValue("");
  192. queryManager.addBindValue(0);
  193. QJsonObject status = queryManager.exec();
  194. if (status["success"].toBool()) {
  195. updateStudentView();
  196. }
  197. }
  198. void StudentPage::setDefault() {}
  199. void StudentPage::removeStudent()
  200. {
  201. StudentTableModel *model = qobject_cast<StudentTableModel *>(studentView->model());
  202. const QModelIndex index = studentView->currentIndex();
  203. StudentTableModel::Student student = model->getCurrentStudent(index);
  204. if (student.id == 0) {
  205. return;
  206. }
  207. UserModel userModel(storage);
  208. CWF::SqlQueryManager queryManager(storage);
  209. //queryManager.select("*", examsModel.getTableName()).where("isSelect = ?");
  210. queryManager.remove(userModel.getTableName(), "id = ?");
  211. queryManager.prepare();
  212. queryManager.addBindValue(student.id);
  213. QJsonObject status = queryManager.exec();
  214. if (status["success"].toBool()) {
  215. updateStudentView();
  216. studentView->setCurrentIndex(index);
  217. }
  218. }
  219. void StudentPage::save()
  220. {
  221. StudentTableModel *model = qobject_cast<StudentTableModel *>(studentView->model());
  222. const QModelIndex index = studentView->currentIndex();
  223. StudentTableModel::Student student = model->getCurrentStudent(index);
  224. if (student.id == 0) {
  225. return;
  226. }
  227. UserModel userModel(storage);
  228. CWF::SqlQueryManager queryManager(storage);
  229. queryManager
  230. .update(userModel.getTableName(),
  231. "name=?,swID=?,state=?,examineeNumber=?,checkinNumber=?,groupName=?,examTest=?")
  232. .where("id = ?");
  233. queryManager.prepare();
  234. queryManager.addBindValue(studentNameLineEdit->text());
  235. queryManager.addBindValue(studentSwLineEdit->text());
  236. queryManager.addBindValue("0");
  237. queryManager.addBindValue(examineeNumberLineEdit->text());
  238. queryManager.addBindValue(checkinNumberLineEdit->text());
  239. queryManager.addBindValue(groupNameComboBox->currentText());
  240. queryManager.addBindValue(examsTestLineEdit->text());
  241. queryManager.addBindValue(student.id);
  242. QJsonObject status = queryManager.exec();
  243. if (status["success"].toBool()) {
  244. updateStudentView();
  245. studentView->setCurrentIndex(index);
  246. }
  247. }
  248. void StudentPage::Clear()
  249. {
  250. QMessageBox msgBox;
  251. msgBox.setInformativeText(QString(tr("This will clear up all grades and student information")));
  252. msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
  253. msgBox.setDefaultButton(QMessageBox::Ok);
  254. msgBox.setButtonText(QMessageBox::Ok, tr("OK"));
  255. msgBox.setButtonText(QMessageBox::Cancel, tr("Cancel"));
  256. int ret = msgBox.exec();
  257. if (ret == QMessageBox::Ok) {
  258. CWF::SqlQueryManager queryManager(storage);
  259. queryManager.exec("DELETE FROM user;");
  260. queryManager.exec("DELETE FROM exams_test;");
  261. }
  262. // 清理学生信息
  263. updateStudentView();
  264. // 通知成绩信息更新
  265. AppEvent::instance()->examsTestUpdate();
  266. }
  267. void StudentPage::importFile()
  268. {
  269. QString filePath = QFileDialog::getOpenFileName(nullptr,
  270. tr("file"),
  271. "",
  272. "xlsx Files (*.xlsx);;All Files (*)");
  273. // 如果用户选择了文件,输出文件路径
  274. if (filePath.isEmpty()) {
  275. return;
  276. }
  277. QXlsx::Document xlsx = QXlsx::Document(filePath);
  278. int nameIndex = -1;
  279. int SWIDIndex = -1;
  280. int examineeNumberIndex = -1;
  281. int examTestIndex = -1;
  282. int groupIndex = -1;
  283. int maxTimeIndex = -1;
  284. int timeIndex = -1;
  285. int AnswerFileNameIndex = -1;
  286. int checkinNumberIndex = -1;
  287. int schoolIndex = -1;
  288. for (int col = 0; col < 20; ++col) {
  289. QVariant value = xlsx.read(1, col);
  290. QString strValue = value.toString();
  291. qDebug() << strValue;
  292. if (strValue == "\xE5\xA7\x93\xE5\x90\x8D") { // UTF-8 编码的 "姓名"
  293. nameIndex = col;
  294. } else if (strValue == "\x53\x57\x5F\x49\x44") { // UTF-8 编码的 "SW_ID"
  295. SWIDIndex = col;
  296. } else if (strValue == "\xE8\x80\x83\xE8\xAF\x95\xE7\xBC\x96\xE5\x8F\xB7"
  297. || strValue == "赛队编号") { // UTF-8 编码的 "考试编号"
  298. examineeNumberIndex = col;
  299. } else if (strValue
  300. == "\xE8\x80\x83\xE8\xAF\x95\xE5\x86\x85\xE5\xAE\xB9") { // UTF-8 编码的 "考试内容"
  301. examTestIndex = col;
  302. } else if (strValue == "\xE7\xBB\x84\xE5\x88\xAB") { // UTF-8 编码的 "组别"
  303. groupIndex = col;
  304. } else if (strValue
  305. == "\xE6\x9C\x80\xE5\xA4\xA7\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97"
  306. "\xB4") { // UTF-8 编码的 "最大完成时间"
  307. maxTimeIndex = col;
  308. } else if (strValue
  309. == "\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4") { // UTF-8 编码的 "完成时间"
  310. timeIndex = col;
  311. } else if (strValue
  312. == "\xE7\xAD\x94\xE6\xA1\x88\xE6\x96\x87\xE4\xBB\xB6\xE5\x90\x8D\xE7\xA7"
  313. "\xB0") { // UTF-8 编码的 "答案文件名称"
  314. AnswerFileNameIndex = col;
  315. } else if (strValue == "\347\255\276\345\210\260\345\217\267"
  316. || strValue == "座位号") { // UTF-8 编码的 "签到号"
  317. checkinNumberIndex = col;
  318. } else if (strValue == "\345\255\246\346\240\241") { // UTF-8 编码的 "学校"
  319. schoolIndex = col;
  320. }
  321. }
  322. UserModel userModel(storage);
  323. for (int row = 2;; ++row) {
  324. QVariant nameValue = xlsx.read(row, nameIndex);
  325. QVariant SWIDValue = xlsx.read(row, SWIDIndex);
  326. QVariant examineeNumberValue = xlsx.read(row, examineeNumberIndex);
  327. QVariant examTestValue = xlsx.read(row, examTestIndex);
  328. QVariant groupNameValue = xlsx.read(row, groupIndex);
  329. QVariant maxTimeValue = xlsx.read(row, maxTimeIndex);
  330. QVariant timeValue = xlsx.read(row, timeIndex);
  331. QVariant AnswerFileNameValue = xlsx.read(row, AnswerFileNameIndex);
  332. QVariant checkinNumberValue = xlsx.read(row, checkinNumberIndex);
  333. QVariant schoolValue = xlsx.read(row, schoolIndex);
  334. if (nameValue.isNull() && SWIDValue.isNull() && examineeNumberValue.isNull()
  335. && examTestValue.isNull() && groupNameValue.isNull() && maxTimeValue.isNull()
  336. && timeValue.isNull() && AnswerFileNameValue.isNull() && checkinNumberValue.isNull()) {
  337. break;
  338. }
  339. qDebug() << "Row:" << row //
  340. << "Name:" << nameValue.toString() //
  341. << "SWID:" << SWIDValue.toString() //
  342. << "Examinee Number:" << examineeNumberValue.toString() //
  343. << "Exam Test:" << examTestValue.toString() //
  344. << "Group:" << groupNameValue.toString() //
  345. << "Max Time:" << maxTimeValue.toString() //
  346. << "Time:" << timeValue.toString() //
  347. << "Answer File Name:" << AnswerFileNameValue.toString() //
  348. << "checkin Number Value" << checkinNumberValue.toString();
  349. if (nameValue.isNull()) {
  350. // 错误处理
  351. }
  352. // 考试编号 和 SW_ID 必须存在一个
  353. if (examineeNumberValue.isNull() && SWIDValue.isNull()) {
  354. // 错误处理
  355. continue;
  356. }
  357. CWF::SqlQueryManager queryManager(storage);
  358. queryManager.insert(
  359. userModel.getTableName(),
  360. "name,swID,examineeNumber,examTest,groupName,maxTime,checkinNumber,school,state");
  361. queryManager.prepare();
  362. queryManager.addBindValue(nameValue.toString());
  363. queryManager.addBindValue(SWIDValue.toString());
  364. queryManager.addBindValue(examineeNumberValue.toString());
  365. queryManager.addBindValue(examTestValue.toString());
  366. queryManager.addBindValue(groupNameValue.toString());
  367. queryManager.addBindValue(maxTimeValue.toInt());
  368. queryManager.addBindValue(checkinNumberValue.toString());
  369. queryManager.addBindValue(schoolValue.toString());
  370. queryManager.addBindValue("0");
  371. QJsonObject status = queryManager.exec();
  372. if (status["success"].toBool()) {
  373. updateStudentView();
  374. }
  375. }
  376. }
  377. void StudentPage::exportFile()
  378. {
  379. QString filePath = QFileDialog::getSaveFileName(nullptr,
  380. tr("file"),
  381. "",
  382. "xlsx Files (*.xlsx);;All Files (*)");
  383. // 如果用户选择了文件,输出文件路径
  384. if (filePath.isEmpty()) {
  385. return;
  386. }
  387. QXlsx::Document xlsx = QXlsx::Document(filePath);
  388. int nameIndex = 1;
  389. int SWIDIndex = 2;
  390. int examineeNumberIndex = 3;
  391. int examTestIndex = 4;
  392. int groupIndex = 5;
  393. int maxTimeIndex = 6;
  394. int timeIndex = 7;
  395. int AnswerFileNameIndex = 8;
  396. int checkinNumberIndex = 9; //
  397. int timeSecondIndex = 10;
  398. int schoolIndex = 11;
  399. QStringList colName = {
  400. "",
  401. "\xE5\xA7\x93\xE5\x90\x8D", // UTF-8 编码的 "姓名"
  402. "\x53\x57\x5F\x49\x44", // UTF-8 编码的 "SW_ID"
  403. "\xE8\x80\x83\xE8\xAF\x95\xE7\xBC\x96\xE5\x8F\xB7", // UTF-8 编码的 "考试编号"
  404. "\xE8\x80\x83\xE8\xAF\x95\xE5\x86\x85\xE5\xAE\xB9", // UTF-8 编码的 "考试内容"
  405. "\xE7\xBB\x84\xE5\x88\xAB", // UTF-8 编码的 "组别"
  406. "\xE6\x9C\x80\xE5\xA4\xA7\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4", // UTF-8 编码的 "最大完成时间"
  407. "\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4", // UTF-8 编码的 "完成时间"
  408. "\xE7\xAD\x94\xE6\xA1\x88\xE6\x96\x87\xE4\xBB\xB6\xE5\x90\x8D\xE7\xA7\xB0", // UTF-8 编码的 "答案文件名称"
  409. "\347\255\276\345\210\260\345\217\267", // UTF-8 编码的 "签到号"
  410. "\347\247\222", // 秒
  411. "\345\255\246\346\240\241" // 学校
  412. };
  413. for (int col = 1; col < colName.size(); ++col) {
  414. QVariant value = xlsx.read(1, col);
  415. QString strValue = value.toString();
  416. xlsx.write(1, col, colName[col]);
  417. }
  418. UserModel userModel(storage);
  419. CWF::SqlQueryManager queryManager(storage);
  420. queryManager.select("*", userModel.getTableName());
  421. int row = 2;
  422. QJsonObject status = queryManager.exec(queryManager.getQueryText());
  423. if (status["success"].toBool()) {
  424. const QJsonArray jsonArray = queryManager.toJson();
  425. for (const QJsonValue &json : jsonArray) {
  426. const QJsonObject &object = json.toObject();
  427. // QString name; // 姓名
  428. // QString swID; // SW_ID
  429. // QString state; // 在线状态
  430. // QString examineeNumber; // 考试编号
  431. // QString examTest; // 考试内容
  432. // QString checkinNumber; // 签到号
  433. // QString groupName; // 组别
  434. // int maxTime; // 最大完成时间
  435. // int answerTime; // 完成时间
  436. // QString answerFileName; // 完成时间
  437. QString name = object["name"].toString(); // 姓名
  438. QString swID = object["SW_ID"].toString(); // SW_ID
  439. QString state = object["state"].toString(); // 在线状态
  440. QString examineeNumber = object["examineeNumber"].toString(); // 考试编号
  441. QString examTest = object["examTest"].toString(); // 考试内容
  442. QString checkinNumber = object["checkinNumber"].toString(); // 签到号
  443. QString groupName = object["groupName"].toString(); // 组别
  444. int maxTime = object["maxTime"].toInt(); // 最大完成时间
  445. int answerTime = object["answerTime"].toInt(); // 完成时间
  446. QString answerFileName = object["answerFileName"].toString(); // 答案文件名称
  447. QString school = object["school"].toString(); // 答案文件名称
  448. // Writing data to Excel file
  449. xlsx.write(row, nameIndex, name);
  450. xlsx.write(row, SWIDIndex, swID);
  451. xlsx.write(row, examineeNumberIndex, examineeNumber);
  452. xlsx.write(row, examTestIndex, examTest);
  453. xlsx.write(row, groupIndex, groupName);
  454. xlsx.write(row, maxTimeIndex, maxTime);
  455. xlsx.write(row, timeIndex, answerTime);
  456. xlsx.write(row, AnswerFileNameIndex, answerFileName);
  457. xlsx.write(row, checkinNumberIndex, checkinNumber);
  458. xlsx.write(row, timeSecondIndex, int(answerTime / 1000));
  459. xlsx.write(row, schoolIndex, school);
  460. row++;
  461. }
  462. }
  463. xlsx.save();
  464. }