studentpage.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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 < 8; ++col) {
  289. QVariant value = xlsx.read(1, col);
  290. QString strValue = value.toString();
  291. if (strValue == "\xE5\xA7\x93\xE5\x90\x8D") { // UTF-8 编码的 "姓名"
  292. nameIndex = col;
  293. } else if (strValue == "\x53\x57\x5F\x49\x44") { // UTF-8 编码的 "SW_ID"
  294. SWIDIndex = col;
  295. } else if (strValue
  296. == "\xE8\x80\x83\xE8\xAF\x95\xE7\xBC\x96\xE5\x8F\xB7") { // UTF-8 编码的 "考试编号"
  297. examineeNumberIndex = col;
  298. } else if (strValue
  299. == "\xE8\x80\x83\xE8\xAF\x95\xE5\x86\x85\xE5\xAE\xB9") { // UTF-8 编码的 "考试内容"
  300. examTestIndex = col;
  301. } else if (strValue == "\xE7\xBB\x84\xE5\x88\xAB") { // UTF-8 编码的 "组别"
  302. groupIndex = col;
  303. } else if (strValue
  304. == "\xE6\x9C\x80\xE5\xA4\xA7\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97" "\xB4") { // UTF-8 编码的 "最大完成时间"
  305. maxTimeIndex = col;
  306. } else if (strValue
  307. == "\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4") { // UTF-8 编码的 "完成时间"
  308. timeIndex = col;
  309. } else if (strValue
  310. == "\xE7\xAD\x94\xE6\xA1\x88\xE6\x96\x87\xE4\xBB\xB6\xE5\x90\x8D\xE7\xA7" "\xB0") { // UTF-8 编码的 "答案文件名称"
  311. AnswerFileNameIndex = col;
  312. } else if (strValue == "\347\255\276\345\210\260\345\217\267") { // UTF-8 编码的 "签到号"
  313. checkinNumberIndex = col;
  314. } else if (strValue == "\345\255\246\346\240\241") { // UTF-8 编码的 "学校"
  315. schoolIndex = col;
  316. }
  317. }
  318. UserModel userModel(storage);
  319. for (int row = 2;; ++row) {
  320. QVariant nameValue = xlsx.read(row, nameIndex);
  321. QVariant SWIDValue = xlsx.read(row, SWIDIndex);
  322. QVariant examineeNumberValue = xlsx.read(row, examineeNumberIndex);
  323. QVariant examTestValue = xlsx.read(row, examTestIndex);
  324. QVariant groupNameValue = xlsx.read(row, groupIndex);
  325. QVariant maxTimeValue = xlsx.read(row, maxTimeIndex);
  326. QVariant timeValue = xlsx.read(row, timeIndex);
  327. QVariant AnswerFileNameValue = xlsx.read(row, AnswerFileNameIndex);
  328. QVariant checkinNumberValue = xlsx.read(row, checkinNumberIndex);
  329. QVariant schoolValue = xlsx.read(row, schoolIndex);
  330. if (nameValue.isNull() && SWIDValue.isNull() && examineeNumberValue.isNull()
  331. && examTestValue.isNull() && groupNameValue.isNull() && maxTimeValue.isNull()
  332. && timeValue.isNull() && AnswerFileNameValue.isNull() && checkinNumberValue.isNull()) {
  333. break;
  334. }
  335. qDebug() << "Row:" << row //
  336. << "Name:" << nameValue.toString() //
  337. << "SWID:" << SWIDValue.toString() //
  338. << "Examinee Number:" << examineeNumberValue.toString() //
  339. << "Exam Test:" << examTestValue.toString() //
  340. << "Group:" << groupNameValue.toString() //
  341. << "Max Time:" << maxTimeValue.toString() //
  342. << "Time:" << timeValue.toString() //
  343. << "Answer File Name:" << AnswerFileNameValue.toString() //
  344. << "checkin Number Value" << checkinNumberValue.toString();
  345. if (nameValue.isNull()) {
  346. // 错误处理
  347. }
  348. // 考试编号 和 SW_ID 必须存在一个
  349. if (examineeNumberValue.isNull() && SWIDValue.isNull()) {
  350. // 错误处理
  351. continue;
  352. }
  353. CWF::SqlQueryManager queryManager(storage);
  354. queryManager.insert(
  355. userModel.getTableName(),
  356. "name,swID,examineeNumber,examTest,groupName,maxTime,checkinNumber,school,state");
  357. queryManager.prepare();
  358. queryManager.addBindValue(nameValue.toString());
  359. queryManager.addBindValue(SWIDValue.toString());
  360. queryManager.addBindValue(examineeNumberValue.toString());
  361. queryManager.addBindValue(examTestValue.toString());
  362. queryManager.addBindValue(groupNameValue.toString());
  363. queryManager.addBindValue(maxTimeValue.toInt());
  364. queryManager.addBindValue(checkinNumberValue.toString());
  365. queryManager.addBindValue(schoolValue.toString());
  366. queryManager.addBindValue("0");
  367. QJsonObject status = queryManager.exec();
  368. if (status["success"].toBool()) {
  369. updateStudentView();
  370. }
  371. }
  372. }
  373. void StudentPage::exportFile()
  374. {
  375. QString filePath = QFileDialog::getSaveFileName(nullptr,
  376. tr("file"),
  377. "",
  378. "xlsx Files (*.xlsx);;All Files (*)");
  379. // 如果用户选择了文件,输出文件路径
  380. if (filePath.isEmpty()) {
  381. return;
  382. }
  383. QXlsx::Document xlsx = QXlsx::Document(filePath);
  384. int nameIndex = 1;
  385. int SWIDIndex = 2;
  386. int examineeNumberIndex = 3;
  387. int examTestIndex = 4;
  388. int groupIndex = 5;
  389. int maxTimeIndex = 6;
  390. int timeIndex = 7;
  391. int AnswerFileNameIndex = 8;
  392. int checkinNumberIndex = 9; //
  393. int timeSecondIndex = 10;
  394. int schoolIndex = 11;
  395. QStringList colName = {
  396. "",
  397. "\xE5\xA7\x93\xE5\x90\x8D", // UTF-8 编码的 "姓名"
  398. "\x53\x57\x5F\x49\x44", // UTF-8 编码的 "SW_ID"
  399. "\xE8\x80\x83\xE8\xAF\x95\xE7\xBC\x96\xE5\x8F\xB7", // UTF-8 编码的 "考试编号"
  400. "\xE8\x80\x83\xE8\xAF\x95\xE5\x86\x85\xE5\xAE\xB9", // UTF-8 编码的 "考试内容"
  401. "\xE7\xBB\x84\xE5\x88\xAB", // UTF-8 编码的 "组别"
  402. "\xE6\x9C\x80\xE5\xA4\xA7\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4", // UTF-8 编码的 "最大完成时间"
  403. "\xE5\xAE\x8C\xE6\x88\x90\xE6\x97\xB6\xE9\x97\xB4", // UTF-8 编码的 "完成时间"
  404. "\xE7\xAD\x94\xE6\xA1\x88\xE6\x96\x87\xE4\xBB\xB6\xE5\x90\x8D\xE7\xA7\xB0", // UTF-8 编码的 "答案文件名称"
  405. "\347\255\276\345\210\260\345\217\267", // UTF-8 编码的 "签到号"
  406. "\347\247\222", // 秒
  407. "\345\255\246\346\240\241" // 学校
  408. };
  409. for (int col = 1; col < colName.size(); ++col) {
  410. QVariant value = xlsx.read(1, col);
  411. QString strValue = value.toString();
  412. xlsx.write(1, col, colName[col]);
  413. }
  414. UserModel userModel(storage);
  415. CWF::SqlQueryManager queryManager(storage);
  416. queryManager.select("*", userModel.getTableName());
  417. int row = 2;
  418. QJsonObject status = queryManager.exec(queryManager.getQueryText());
  419. if (status["success"].toBool()) {
  420. const QJsonArray jsonArray = queryManager.toJson();
  421. for (const QJsonValue &json : jsonArray) {
  422. const QJsonObject &object = json.toObject();
  423. // QString name; // 姓名
  424. // QString swID; // SW_ID
  425. // QString state; // 在线状态
  426. // QString examineeNumber; // 考试编号
  427. // QString examTest; // 考试内容
  428. // QString checkinNumber; // 签到号
  429. // QString groupName; // 组别
  430. // int maxTime; // 最大完成时间
  431. // int answerTime; // 完成时间
  432. // QString answerFileName; // 完成时间
  433. QString name = object["name"].toString(); // 姓名
  434. QString swID = object["SW_ID"].toString(); // SW_ID
  435. QString state = object["state"].toString(); // 在线状态
  436. QString examineeNumber = object["examineeNumber"].toString(); // 考试编号
  437. QString examTest = object["examTest"].toString(); // 考试内容
  438. QString checkinNumber = object["checkinNumber"].toString(); // 签到号
  439. QString groupName = object["groupName"].toString(); // 组别
  440. int maxTime = object["maxTime"].toInt(); // 最大完成时间
  441. int answerTime = object["answerTime"].toInt(); // 完成时间
  442. QString answerFileName = object["answerFileName"].toString(); // 答案文件名称
  443. QString school = object["school"].toString(); // 答案文件名称
  444. // Writing data to Excel file
  445. xlsx.write(row, nameIndex, name);
  446. xlsx.write(row, SWIDIndex, swID);
  447. xlsx.write(row, examineeNumberIndex, examineeNumber);
  448. xlsx.write(row, examTestIndex, examTest);
  449. xlsx.write(row, groupIndex, groupName);
  450. xlsx.write(row, maxTimeIndex, maxTime);
  451. xlsx.write(row, timeIndex, answerTime);
  452. xlsx.write(row, AnswerFileNameIndex, answerFileName);
  453. xlsx.write(row, checkinNumberIndex, checkinNumber);
  454. xlsx.write(row, timeSecondIndex, int(answerTime / 1000));
  455. xlsx.write(row, schoolIndex, school);
  456. row++;
  457. }
  458. }
  459. xlsx.save();
  460. }