studentpage.cpp 21 KB

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