#include "answerWidget.h" #include "ui_answerWidget.h" #include "CAppInfo.h" #include "awMsgBox.h" #include "awQuestionNavigate.h" #include "CCommonTools.h" #include "logproc.h" #include "inprogressFace.h" answerWidget::answerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::answerWidget) { ui->setupUi(this); setStyleSheet(g_appInfoPtr->m_sQssStr); qRegisterMetaType("CGetExamById"); connect(g_httpBllPtr.get(), &CHttpBll::sgnGetExamById, this, &answerWidget::onGetExamById); qRegisterMetaType("CGetExamRecordPaperStruct"); connect(g_httpBllPtr.get(), &CHttpBll::sgnGetExamRecordPaperStruct, this, &answerWidget::onGetExamRecordPaperStruct); qRegisterMetaType("CGetExamProperty"); connect(g_httpBllPtr.get(), &CHttpBll::sgnGetExamProperty, this, &answerWidget::onGetExamProperty); qRegisterMetaType("CWeiXinAnswerEnabled"); connect(g_httpBllPtr.get(), &CHttpBll::sgnWeiXinAnswerEnabled, this, &answerWidget::onWeiXinAnswerEnabled); qRegisterMetaType("CGetQuestionContent"); connect(g_httpBllPtr.get(), &CHttpBll::sgnGetQuestionContent, this, &answerWidget::onGetQuestionContent); qRegisterMetaType("CFindExamQuestionList"); connect(g_httpBllPtr.get(), &CHttpBll::sgnFindExamQuestionList, this, &answerWidget::onFindExamQuestionList); qRegisterMetaType("CStartAnswer"); connect(g_httpBllPtr.get(), &CHttpBll::sgnStartAnswer, this, &answerWidget::onStartAnswer); qRegisterMetaType("CExamHeartbeat"); connect(g_httpBllPtr.get(), &CHttpBll::sgnExamHeartbeat, this, &answerWidget::onExamHeartbeat); qRegisterMetaType("CSubmitQuestionAnswer"); connect(g_httpBllPtr.get(), &CHttpBll::sgnSubmitQuestionAnswer, this, &answerWidget::onSubmitQuestionAnswer); qRegisterMetaType("CEndExam"); connect(g_httpBllPtr.get(), &CHttpBll::sgnEndExam, this, &answerWidget::onEndExam); qRegisterMetaType("CGetOrgPropertiesByGroupWithoutCache"); connect(g_httpBllPtr.get(), &CHttpBll::sgnGetOrgPropertiesByGroupWithoutCache, this, &answerWidget::onGetOrgPropertiesByGroupWithoutCache); qRegisterMetaType("CStartFaceLiveVerify"); connect(g_httpBllPtr.get(), &CHttpBll::sgnStartFaceLiveVerify, this, &answerWidget::onStartFaceLiveVerify); m_nLeftSeconds = 0; CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_exam_work/exam/getExamPropertyFromCacheByStudentSession/%1/%2") .arg(g_appInfoPtr->m_oExamInfo.nExamId).arg("SNAPSHOT_INTERVAL,PRACTICE_TYPE,FREEZE_TIME,PRACTICE_TYPE"); hrp.nRequestType = RequestType::rtGetExamProperty; hrp.sCommonStr = "SNAPSHOT_INTERVAL,PRACTICE_TYPE,FREEZE_TIME"; g_httpBllPtr->get(hrp); { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_exam_work/exam/%1").arg(g_appInfoPtr->m_oExamInfo.nExamId); hrp.nRequestType = RequestType::rtGetExamById; g_httpBllPtr->get(hrp); } CHttpRequestPackage hrp1; hrp1.sUri = "/api/ecs_oe_student/client/exam/process/getExamRecordPaperStruct"; hrp1.sParamList.push_back(QString("examRecordDataId,%1").arg(g_appInfoPtr->m_oExamInfo.nExamRecordDataId)); hrp1.nRequestType = RequestType::rtGetExamRecordPaperStruct; hrp1.eParamType = HttpParamType::hptUrl; g_httpBllPtr->post(hrp1); { CHttpRequestPackage hrp; hrp.sUri = "/api/ecs_oe_student/client/exam/process/findExamQuestionList"; hrp.nRequestType = RequestType::rtFindExamQuestionList; g_httpBllPtr->post(hrp); } { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_exam_work/exam/weixinAnswerEnabled/%1") .arg(g_appInfoPtr->m_oExamInfo.nExamId); hrp.nRequestType = RequestType::rtWeiXinAnswerEnabled; g_httpBllPtr->get(hrp); } m_pCountDownTimer = std::make_shared(); m_pCountDownTimer->setInterval(1000); connect(m_pCountDownTimer.get(), &QTimer::timeout, this, [&](){ --m_nLeftSeconds; ui->label_lastTime->setText(QString("%1:%2:%3").arg(m_nLeftSeconds/60/60, 2, 10, QChar('0')) .arg(m_nLeftSeconds/60%60, 2, 10, QChar('0')) .arg(m_nLeftSeconds%60, 2, 10, QChar('0'))); if(m_nLeftSeconds <= 0) { m_pCountDownTimer->stop(); handinPaper(); } if(g_appInfoPtr->m_oExamInfo.bLivenessCheck && g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId > 0) { if(bShowLivenessTip && ((g_appInfoPtr->m_oExamInfo.nDuration - g_appInfoPtr->m_oExamInfo.nFaceVerifyDoMinute)*60 + g_appInfoPtr->m_oExamInfo.nActionAlert) > m_nLeftSeconds) { bShowLivenessTip = false; ShowMsg(QString::fromLocal8Bit("%1秒后开始指定动作检测,请准备!").arg(g_appInfoPtr->m_oExamInfo.nActionAlert), g_appInfoPtr->m_pAnsBgWidget); } if((g_appInfoPtr->m_oExamInfo.nDuration - g_appInfoPtr->m_oExamInfo.nFaceVerifyDoMinute)*60 > m_nLeftSeconds) { //活体检测 if(m_pFaceLiveness == nullptr) { stopCapture(); m_pFaceLiveness = std::make_shared(g_appInfoPtr->m_pAnsBgWidget); connect(m_pFaceLiveness.get(), &faceLiveness::faceLivenessFaild, this, [&](){ g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId = 0; m_pFaceLiveness.reset(); if(g_appInfoPtr->m_oExamInfo.nFaceVerifyTimes < 2) { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/startFaceLiveVerify") .arg(g_appInfoPtr->m_sRootOrgId); hrp.nRequestType = RequestType::rtStartFaceLiveVerify; hrp.sParamList.push_back(QString("examRecordDataId,%1").arg(g_appInfoPtr->m_oExamInfo.nExamRecordDataId)); hrp.eParamType = HttpParamType::hptUrl; g_httpBllPtr->post(hrp); } startCapture(); }); connect(m_pFaceLiveness.get(), &faceLiveness::faceLivenessSucceed, this, [&](){ g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId = 0; m_pFaceLiveness.reset(); startCapture(); }); m_pFaceLiveness->show(); } } } }); m_pHeartbeatTimer = std::make_shared(); m_pHeartbeatTimer->setInterval(60*1000); connect(m_pHeartbeatTimer.get(), &QTimer::timeout, this, [&](){ heartBreat(); }); } answerWidget::~answerWidget() { delete ui; } void answerWidget::setUI(const int nLeft, const int nTop, const int nWidth, const int nHeight) { setGeometry(nLeft, nTop, nWidth, nHeight); ui->widget_aw_answerBG->setGeometry(0, 0, width()*970/(970+270), height()); ui->widget_navigate->setGeometry(ui->widget_aw_answerBG->x() + ui->widget_aw_answerBG->width() + g_appInfoPtr->m_fRate*20, 0, width() - ui->widget_aw_answerBG->width() - g_appInfoPtr->m_fRate*20, height()); ui->widget_aw_face->setGeometry(0, ui->widget_navigate->height() - g_appInfoPtr->m_fRate*140, ui->widget_navigate->width(), g_appInfoPtr->m_fRate*140); ui->widget_aw_top->setGeometry(0, 0, ui->widget_aw_answerBG->width(), g_appInfoPtr->m_fRate*56); ui->widget_ng_top->setGeometry(0, 0, ui->widget_navigate->width(), g_appInfoPtr->m_fRate*56); ui->label_answerProgress->adjustSize(); ui->label_answerProgress->setGeometry(g_appInfoPtr->m_fRate*20, (ui->widget_aw_top->height() - ui->label_answerProgress->height())/2, ui->label_answerProgress->width(), ui->label_answerProgress->height()); ui->pgb_answerProgress->setGeometry(ui->label_answerProgress->x() + ui->label_answerProgress->width() + g_appInfoPtr->m_fRate*8, (ui->widget_aw_top->height() - g_appInfoPtr->m_fRate*20)/2, g_appInfoPtr->m_fRate*200, g_appInfoPtr->m_fRate*20); ui->btn_handInPaper->setGeometry(ui->widget_aw_top->width() - g_appInfoPtr->m_fRate*(10 + 100), g_appInfoPtr->m_fRate*10, g_appInfoPtr->m_fRate*100, g_appInfoPtr->m_fRate*36); ui->label_lastTimeIcon->setGeometry(g_appInfoPtr->m_fRate*48, g_appInfoPtr->m_fRate*12, g_appInfoPtr->m_fRate*32, g_appInfoPtr->m_fRate*32); ui->label_lastTime->adjustSize(); ui->label_lastTime->setGeometry(ui->label_lastTimeIcon->x() + ui->label_lastTimeIcon->width() + g_appInfoPtr->m_fRate*10, ui->label_lastTimeIcon->y() + (ui->label_lastTimeIcon->height() - ui->label_lastTime->height())/2, ui->label_lastTime->width(), ui->label_lastTime->height()); ui->btn_all->setGeometry(g_appInfoPtr->m_fRate*30, ui->widget_ng_top->height() + g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*90, 28); ui->btn_allNum->setGeometry(ui->btn_all->x() + ui->btn_all->width() - g_appInfoPtr->m_fRate*(4 + 30), ui->btn_all->y() + (ui->btn_all->height() - g_appInfoPtr->m_fRate*20)/2, g_appInfoPtr->m_fRate*30, g_appInfoPtr->m_fRate*20); ui->btn_answered->setGeometry(ui->btn_all->x() + ui->btn_all->width() + g_appInfoPtr->m_fRate*10, ui->btn_all->y(), ui->btn_all->width(), ui->btn_all->height()); ui->btn_answeredNum->setGeometry(ui->btn_answered->x() + ui->btn_answered->width() - g_appInfoPtr->m_fRate*(4 + 30), ui->btn_allNum->y(), ui->btn_allNum->width(), ui->btn_allNum->height()); ui->btn_unanswered->setGeometry(ui->btn_all->x(), ui->btn_all->y() + ui->btn_all->height() + g_appInfoPtr->m_fRate*10, ui->btn_all->width(), ui->btn_all->height()); ui->btn_unansweredNum->setGeometry(ui->btn_allNum->x(), ui->btn_unanswered->y() + (ui->btn_unanswered->height() - g_appInfoPtr->m_fRate*20)/2, ui->btn_allNum->width(), ui->btn_allNum->height()); ui->btn_marked->setGeometry(ui->btn_answered->x(), ui->btn_unanswered->y(), ui->btn_all->width(), ui->btn_all->height()); ui->btn_markedNum->setGeometry(ui->btn_answeredNum->x(), ui->btn_unansweredNum->y(), ui->btn_allNum->width(), ui->btn_allNum->height()); ui->label_HLine->setGeometry(ui->btn_all->x(), ui->btn_unanswered->y() + ui->btn_unanswered->height() + g_appInfoPtr->m_fRate*20, ui->widget_navigate->width() - ui->btn_all->x()*2, g_appInfoPtr->m_fRate*1); ui->lw_aw_questionList->setGeometry(0, ui->label_HLine->y(), ui->widget_navigate->width(), ui->widget_aw_face->y() - ui->label_HLine->y() - ui->label_HLine->height()); } void answerWidget::onGetExamById(CGetExamById getExamById) { if (getExamById.nCode == 200) { g_appInfoPtr->m_oExamInfo.nExamId = getExamById.nId; g_appInfoPtr->m_oExamInfo.sExamType = getExamById.sExamType; g_appInfoPtr->m_oExamInfo.nDuration = getExamById.nDuration; } else { if(getExamById.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取考试信息出错"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(getExamById.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onGetExamRecordPaperStruct(CGetExamRecordPaperStruct getExamRecordPaperStruct) { if (getExamRecordPaperStruct.nCode == 200) { m_vPaperGroupStruct.swap(getExamRecordPaperStruct.vPaperGroupStruct); int nSize = m_vPaperGroupStruct.size(); QString sQuestionId = ""; for (int i = 0; i < nSize; ++i) { CPaperGroupStruct &pgs = m_vPaperGroupStruct[i]; awQuestionNavigate *questionItem = new awQuestionNavigate(pgs); connect(questionItem, &awQuestionNavigate::showSubQuestion, this, [&](QString sQuestionId, int nOrder, bool bHasContent) { showQuestionByOrder(nOrder); /*if (bHasContent) { for (CQuestionStruct &qs : pgs.vQuestionStruct) { if (qs.sQuestionId == sQuestionId) { QString sGroupTitleText = QString::fromLocal8Bit("%1、%2 (共%3题)").arg(CCommonTools::Arab2Sinogram(pgs.nNumber)).arg(pgs.sGroupName).arg(pgs.nTotalSubquestion); QString sGroupProgressText = QString::fromLocal8Bit("完成进度(%1/%2)").arg(pgs.nAnsweredCount).arg(pgs.nTotalSubquestion); showSubQuestion(qs, nOrder, sGroupTitleText, sGroupProgressText); } } } else { getQuestionContent(sQuestionId, nOrder); } */ }); QListWidgetItem *pItem = new QListWidgetItem; ui->lw_aw_questionList->addItem(pItem); ui->lw_aw_questionList->setItemWidget(pItem, questionItem); int nHeight = questionItem->setUI(ui->lw_aw_questionList->width() - g_appInfoPtr->m_fRate*60); QSize size = pItem->sizeHint(); size.setHeight(nHeight); pItem->setSizeHint(size); } } else { if(getExamRecordPaperStruct.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取考试结构出错"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(getExamRecordPaperStruct.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } CAnsweredQuestion answerWidget::findQuestionByOrder(CFindExamQuestionList &feql, int nOrder) { for (int i = 0; i < feql.vAnsweredQuestion.size(); ++i) { if (feql.vAnsweredQuestion[i].nOrder == nOrder) { return feql.vAnsweredQuestion[i]; } } } void answerWidget::onFindExamQuestionList(CFindExamQuestionList findExamQuestionList) { if (findExamQuestionList.nCode == 200) { int nTotal = 0; int nAnswered = 0; int nMarked = 0; int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { nTotal++; int nOrder = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k].nOrder; CAnsweredQuestion aq= findQuestionByOrder(findExamQuestionList, nOrder); m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k].bAnswered = aq.bIsAnswer; m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k].bMarked = aq.bIsSign; m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k].sStudentAnswer = aq.sStudentAnswer; if (aq.bIsAnswer) { nAnswered++; } if (aq.bIsSign) { nMarked++; } if (!aq.sAudioPlayTimes.isEmpty()) { Json::Reader reader; Json::Value jAudioPlayTimes = Json::Value::null; if (reader.parse(aq.sAudioPlayTimes.toStdString(), jAudioPlayTimes)) { for (int ja = 0; ja < jAudioPlayTimes.size(); ++ja) { Json::Value jAudioPlayItem = jAudioPlayTimes[ja]; g_appInfoPtr->m_jAudioPlayedCount[jAudioPlayItem["name"].asString()] = jAudioPlayItem["times"].asInt(); } } } } } } showQuestionByOrder(1); ui->btn_allNum->setText(QString::number(nTotal)); ui->btn_answeredNum->setText(QString::number(nAnswered)); ui->btn_markedNum->setText(QString::number(nMarked)); ui->btn_unansweredNum->setText(QString::number(nTotal - nAnswered)); ui->pgb_answerProgress->setMaximum(nTotal); ui->pgb_answerProgress->setValue(nAnswered); refreshStatus(); //开始答题 CHttpRequestPackage hrp1; hrp1.sUri = "/api/ecs_oe_student/client/exam/process/startAnswer"; hrp1.sParamList.push_back(QString("examRecordDataId,%1").arg(g_appInfoPtr->m_oExamInfo.nExamRecordDataId)); hrp1.nRequestType = RequestType::rtStartAnswer; hrp1.eParamType = HttpParamType::hptUrl; g_httpBllPtr->post(hrp1); } else { if(findExamQuestionList.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取题目信息出错"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(findExamQuestionList.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onGetExamProperty(CGetExamProperty getExamProperty) { if (getExamProperty.nCode == 200) { if (getExamProperty.sType == "SNAPSHOT_INTERVAL,PRACTICE_TYPE,FREEZE_TIME") { m_nSnapshotInterval = getExamProperty.nSnapshotInterval; g_appInfoPtr->m_oExamInfo.sPracticeType = getExamProperty.sPracticeType; m_nFreezeTime = getExamProperty.nFreezeTime; } } else { if(getExamProperty.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取考试信息出错"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(getExamProperty.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onWeiXinAnswerEnabled(CWeiXinAnswerEnabled weiXinAnswerEnabled) { if (weiXinAnswerEnabled.nCode == 200) { g_appInfoPtr->m_bWeiXinAnswerEnabled = weiXinAnswerEnabled.bEnabled; } else { if(weiXinAnswerEnabled.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取考试信息失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(weiXinAnswerEnabled.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::showSubQuestion(CQuestionStruct &qs, int nOrder, QString sTitle, QString sProgress) { if (qs.sBody.isEmpty()) { if (m_pQuestion != nullptr) { m_pQuestion.reset(); } if (m_pQuestionSet != nullptr) { m_pQuestionSet.reset(); } m_pQuestion = std::make_shared(qs, nOrder, ui->widget_aw_answerBG); connect(m_pQuestion.get(), &question::uploadAnswer, this, [&](int nIndex, __int64 timeStamp, QString sAnswer){ uploadAnswer(nIndex, sAnswer); }); connect(m_pQuestion.get(), &question::questionAnswered, this, [&](bool bAnswered, int nIndex){ refreshStatus(); int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; if(sqs.nOrder == nIndex) { QString sGroupProgressText = QString::fromLocal8Bit("完成进度(%1/%2)").arg(m_vPaperGroupStruct[i].nAnsweredCount).arg(m_vPaperGroupStruct[i].nTotalSubquestion); m_pQuestion->setGroupInfo("", sGroupProgressText); break; } } } } }); connect(m_pQuestion.get(), &question::markedItem, this, [&](bool bMarked, int nIndex){ refreshStatus(); }); connect(m_pQuestion.get(), &question::previousQuestion, this, [&](int nOrder){ if(nOrder > 1) { showQuestionByOrder(nOrder - 1); } }); connect(m_pQuestion.get(), &question::nextQuestion, this, [&](int nOrder){ showQuestionByOrder(nOrder + 1); }); m_pQuestion->setGroupInfo(sTitle, sProgress); m_pQuestion->setUI(0, g_appInfoPtr->m_fRate * 86, ui->widget_aw_answerBG->width(), ui->widget_aw_answerBG->height() - g_appInfoPtr->m_fRate * (86 + 20)); m_pQuestion->show(); } else { if (m_pQuestion != nullptr) { m_pQuestion.reset(); } if (m_pQuestionSet != nullptr) { m_pQuestionSet.reset(); } m_pQuestionSet = std::make_shared(qs, nOrder, ui->widget_aw_answerBG); connect(m_pQuestionSet.get(), &questionSet::uploadAnswer, this, [&](int nIndex, __int64 timeStamp, QString sAnswer){ uploadAnswer(nIndex, sAnswer); }); connect(m_pQuestionSet.get(), &questionSet::questionAnswered, this, [&](bool bAnswered, int nIndex){ refreshStatus(); int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; if(sqs.nOrder == nIndex) { QString sGroupProgressText = QString::fromLocal8Bit("完成进度(%1/%2)").arg(m_vPaperGroupStruct[i].nAnsweredCount).arg(m_vPaperGroupStruct[i].nTotalSubquestion); m_pQuestionSet->setGroupInfo("", sGroupProgressText); break; } } } } }); connect(m_pQuestionSet.get(), &questionSet::markedItem, this, [&](bool bMarked, int nIndex){ refreshStatus(); }); connect(m_pQuestionSet.get(), &questionSet::previousQuestion, this, [&](int nOrder){ if(nOrder > 1) { showQuestionByOrder(nOrder - 1); } }); connect(m_pQuestionSet.get(), &questionSet::nextQuestion, this, [&](int nOrder){ showQuestionByOrder(nOrder + 1); }); m_pQuestionSet->setGroupInfo(sTitle, sProgress); m_pQuestionSet->setUI(0, g_appInfoPtr->m_fRate * 86, ui->widget_aw_answerBG->width(), ui->widget_aw_answerBG->height() - g_appInfoPtr->m_fRate * (86 + 20)); m_pQuestionSet->show(); } } void answerWidget::refreshStatus() { int nCount = ui->lw_aw_questionList->count(); for(int i = 0; i < nCount; ++i) { awQuestionNavigate *questionItem = dynamic_cast(ui->lw_aw_questionList->itemWidget(ui->lw_aw_questionList->item(i))); if(questionItem) { questionItem->refreshStatus(); } } int nTotal = 0; int nAnswered = 0; int nMarked = 0; int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); int nAnswerCount = 0; for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; nTotal++; if (sqs.bAnswered) { nAnswerCount++; nAnswered++; } if (sqs.bMarked) { nMarked++; } } } m_vPaperGroupStruct[i].nAnsweredCount = nAnswerCount; } ui->btn_allNum->setText(QString::number(nTotal)); ui->btn_answeredNum->setText(QString::number(nAnswered)); ui->btn_markedNum->setText(QString::number(nMarked)); ui->btn_unansweredNum->setText(QString::number(nTotal - nAnswered)); ui->pgb_answerProgress->setMaximum(nTotal); ui->pgb_answerProgress->setValue(nAnswered); } void answerWidget::showQuestionByOrder(int nOrder) { int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); bool bHasContent = m_vPaperGroupStruct[i].vQuestionStruct[j].bHasContent; for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct &sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; sqs.bCurrent = false; if(sqs.nOrder == nOrder) { sqs.bCurrent = true; if (bHasContent) { QString sGroupTitleText = QString::fromLocal8Bit("%1、%2 (共%3题)").arg(CCommonTools::Arab2Sinogram(m_vPaperGroupStruct[i].nNumber)).arg(m_vPaperGroupStruct[i].sGroupName).arg(m_vPaperGroupStruct[i].nTotalSubquestion); QString sGroupProgressText = QString::fromLocal8Bit("完成进度(%1/%2)").arg(m_vPaperGroupStruct[i].nAnsweredCount).arg(m_vPaperGroupStruct[i].nTotalSubquestion); showSubQuestion(m_vPaperGroupStruct[i].vQuestionStruct[j], nOrder, sGroupTitleText, sGroupProgressText); } else { getQuestionContent(m_vPaperGroupStruct[i].vQuestionStruct[j].sQuestionId, nOrder); } } } } } refreshStatus(); } void answerWidget::uploadAnswer(int nIndex, QString sAnswer) { int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; if(!sqs.bUpload) { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/submitQuestionAnswer"); hrp.nRequestType = RequestType::rtSubmitQuestionAnswer; hrp.eParamType = HttpParamType::hptCustomBody; hrp.sParamList.push_back(QString("CustomBody,%1").arg(sAnswer)); hrp.sCommonStr = QString("%1,%2").arg(sqs.nOrder).arg(sqs.nVersion); g_httpBllPtr->post(hrp); } } } } } void answerWidget::onSubmitQuestionAnswer(CSubmitQuestionAnswer submitQuestionAnswer) { if(submitQuestionAnswer.nCode == 200) { int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct &sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; if(sqs.nOrder == submitQuestionAnswer.nOrder && submitQuestionAnswer.nVersion >= sqs.nVersion) { sqs.bUpload = true; break; } } } } } else { if(submitQuestionAnswer.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("提交答案失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(submitQuestionAnswer.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::getQuestionContent(QString sQuestionId, int nOrder) { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/getQuestionContent") .arg(g_appInfoPtr->m_oExamInfo.nExamId); hrp.nRequestType = RequestType::rtGetQuestionContent; hrp.eParamType = HttpParamType::hptUrl; hrp.sCommonStr = sQuestionId + "," + QString::number(nOrder); hrp.sParamList.push_back(QString("questionId,%1").arg(sQuestionId)); g_httpBllPtr->post(hrp); } void answerWidget::onGetQuestionContent(CGetQuestionContent getQuestionContent) { if (getQuestionContent.nCode == 200) { for (CPaperGroupStruct &pgs : m_vPaperGroupStruct) { for (CQuestionStruct &qs : pgs.vQuestionStruct) { if (qs.sQuestionId == getQuestionContent.sQuestionId) { qs.sBody = getQuestionContent.sBody; qs.sVersion = getQuestionContent.sVersion; qs.bhasAudios = getQuestionContent.bhasAudios; for (int i = 0; i < getQuestionContent.vSubQuestion.size(); ++i) { CSubQuestion sq = getQuestionContent.vSubQuestion[i]; qs.vSubQuestionStruct[i].sBody = sq.sBody; qs.vSubQuestionStruct[i].vRightAnswer.swap(sq.vRightAnswer); qs.vSubQuestionStruct[i].vOptions.swap(sq.vOptions); } QString sGroupTitleText = QString::fromLocal8Bit("%1、%2 (共%3题)").arg(CCommonTools::Arab2Sinogram(pgs.nNumber)).arg(pgs.sGroupName).arg(pgs.nTotalSubquestion); QString sGroupProgressText = QString::fromLocal8Bit("完成进度(%1/%2)").arg(pgs.nAnsweredCount).arg(pgs.nTotalSubquestion); showSubQuestion(qs, getQuestionContent.sOrder.toInt(), sGroupTitleText, sGroupProgressText); break; } } } } else { if(getQuestionContent.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取题目内容失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(getQuestionContent.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onStartAnswer(CStartAnswer startAnswer) { if(startAnswer.nCode == 200) { m_pHeartbeatTimer->start(); heartBreat(); //获取活体参数 if (g_appInfoPtr->m_oExamInfo.bLivenessCheck) { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_core/org/getOrgPropertiesByGroupWithoutCache/%1/config4Edit1") .arg(g_appInfoPtr->m_sRootOrgId); hrp.nRequestType = RequestType::rtGetOrgPropertiesByGroupWithoutCache; g_httpBllPtr->get(hrp); { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/startFaceLiveVerify") .arg(g_appInfoPtr->m_sRootOrgId); hrp.nRequestType = RequestType::rtStartFaceLiveVerify; hrp.sParamList.push_back(QString("examRecordDataId,%1").arg(g_appInfoPtr->m_oExamInfo.nExamRecordDataId)); hrp.eParamType = HttpParamType::hptUrl; g_httpBllPtr->post(hrp); } } } else { if(startAnswer.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("开始作答失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(startAnswer.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onGetOrgPropertiesByGroupWithoutCache(CGetOrgPropertiesByGroupWithoutCache orgProperties) { if(orgProperties.nCode == 200) { g_appInfoPtr->m_oExamInfo.nActionNum = orgProperties.nActionNum; g_appInfoPtr->m_oExamInfo.sActionOptions = orgProperties.sActionOptions; g_appInfoPtr->m_oExamInfo.sActionOrder = orgProperties.sActionOrder; g_appInfoPtr->m_oExamInfo.nActionDuration = orgProperties.nActionDuration; g_appInfoPtr->m_oExamInfo.nActionAlert = orgProperties.nActionAlert; } else { if(orgProperties.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("获取考试信息失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(orgProperties.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::onStartFaceLiveVerify(CStartFaceLiveVerify startFaceLiveVerify) { if(startFaceLiveVerify.nCode == 200) { g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId = startFaceLiveVerify.nFaceLiveVerifyId; g_appInfoPtr->m_oExamInfo.nFaceVerifyTimes = startFaceLiveVerify.nTimes; g_appInfoPtr->m_oExamInfo.nFaceVerifyDoMinute = startFaceLiveVerify.nStartMinute; bShowLivenessTip = true; } else { if(startFaceLiveVerify.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("开启活体验证失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(startFaceLiveVerify.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::heartBreat() { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/examHeartbeat"); hrp.nRequestType = RequestType::rtExamHeartbeat; g_httpBllPtr->post(hrp); } void answerWidget::onExamHeartbeat(CExamHeartbeat examHeartbeat) { if (examHeartbeat.nCode == 200) { m_nLeftSeconds = examHeartbeat.nLeftTime/1000; m_pCountDownTimer->start(); //过程中人脸识别 if(g_appInfoPtr->m_oExamInfo.bFaceCheck) { if(g_inProcessFace == nullptr) { g_inProcessFace = std::make_shared(); connect(g_inProcessFace.get(), &CInprogressFace::compareFailed, this, [&](QString sErrorMsg){ ShowMsg(sErrorMsg, g_appInfoPtr->m_pAnsBgWidget); }); startCapture(); } } } else { if(examHeartbeat.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("考试心跳提交失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(examHeartbeat.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::on_btn_handInPaper_clicked() { if((g_appInfoPtr->m_oExamInfo.nDuration - m_nFreezeTime)*60 < m_nLeftSeconds) { ShowMsg(QString::fromLocal8Bit("冻结时间内不允许交卷"), this); return; } if(m_pHandinPaper == nullptr) { m_pHandinPaper = std::make_shared(ui->btn_answeredNum->text().toInt(), ui->btn_unansweredNum->text().toInt(), ui->btn_markedNum->text().toInt(), (QWidget*)(this->parent())); connect(m_pHandinPaper.get(), &awHandinPaper::handinPaper, this, [&](){ m_pHandinPaper.reset(); //交卷 m_pCountDownTimer->stop(); m_pHeartbeatTimer->stop(); if(g_appInfoPtr->m_oExamInfo.bLivenessCheck) { stopCapture(); } if(g_inProcessFace != nullptr) { g_inProcessFace.reset(); } handinPaper(); }); connect(m_pHandinPaper.get(), &awHandinPaper::cancelHandinPaper, this, [&](){ m_pHandinPaper.reset(); }); } m_pHandinPaper->show(); } bool answerWidget::checkAnswer() { bool bRet = true; int nSize = m_vPaperGroupStruct.size(); for (int i = 0; i < nSize; ++i) { int nQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct.size(); for (int j = 0; j < nQuestionSize; ++j) { int nSubQuestionSize = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct.size(); for (int k = 0; k < nSubQuestionSize; ++k) { CSubQuestionStruct sqs = m_vPaperGroupStruct[i].vQuestionStruct[j].vSubQuestionStruct[k]; if (!sqs.bUpload) { bRet = false; CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/submitQuestionAnswer"); hrp.nRequestType = RequestType::rtSubmitQuestionAnswer; hrp.eParamType = HttpParamType::hptCustomBody; hrp.sParamList.push_back(QString("CustomBody,%1").arg(sqs.sUploadAnswer)); hrp.sCommonStr = QString("%1,%2").arg(sqs.nOrder).arg(sqs.nVersion); g_httpBllPtr->post(hrp); } } } } return bRet; } void answerWidget::handinPaper() { if(m_pResumeExam == nullptr) { m_pResumeExam = std::make_shared((QWidget*)(this->parent()), QString::fromLocal8Bit("交卷中请稍候…")); } m_pResumeExam->show(); if (checkAnswer()) { CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/endExam"); hrp.nRequestType = RequestType::rtEndExam; g_httpBllPtr->post(hrp); } else { if (m_pHandinPaperTimer == nullptr) { m_pHandinPaperTimer = std::make_shared(); m_pHandinPaperTimer->setInterval(10 * 1000); connect(m_pHandinPaperTimer.get(), &QTimer::timeout, this, [&]() { if (checkAnswer()) { m_pHandinPaperTimer->stop(); CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/endExam"); hrp.nRequestType = RequestType::rtEndExam; g_httpBllPtr->post(hrp); } }); } } } void answerWidget::onEndExam(CEndExam endExam) { if (endExam.nCode == 200) { m_pResumeExam.reset(); if (g_appInfoPtr->m_oExamInfo.sExamType == EXAM_TYPES::PRACTICE) { if(g_appInfoPtr->m_oExamInfo.sPracticeType != "NO_ANSWER") { emit showPracticeInfo(); } else { emit gobackCourseList(); } } else { emit showExamScore(); } } else { if(endExam.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("交卷失败"), g_appInfoPtr->m_pAnsBgWidget); } else { ShowMsg(endExam.sMessage, g_appInfoPtr->m_pAnsBgWidget); } } } void answerWidget::on_btn_all_clicked() { int nCount = ui->lw_aw_questionList->count(); for(int i = 0; i < nCount; ++i) { awQuestionNavigate *questionItem = dynamic_cast(ui->lw_aw_questionList->itemWidget(ui->lw_aw_questionList->item(i))); if(questionItem) { questionItem->setShowType(ITEM_SHOW_TYPE::ist_showAll); } } } void answerWidget::on_btn_answered_clicked() { int nCount = ui->lw_aw_questionList->count(); for(int i = 0; i < nCount; ++i) { awQuestionNavigate *questionItem = dynamic_cast(ui->lw_aw_questionList->itemWidget(ui->lw_aw_questionList->item(i))); if(questionItem) { questionItem->setShowType(ITEM_SHOW_TYPE::ist_showAnswered); } } } void answerWidget::on_btn_unanswered_clicked() { int nCount = ui->lw_aw_questionList->count(); for(int i = 0; i < nCount; ++i) { awQuestionNavigate *questionItem = dynamic_cast(ui->lw_aw_questionList->itemWidget(ui->lw_aw_questionList->item(i))); if(questionItem) { questionItem->setShowType(ITEM_SHOW_TYPE::ist_showUnanswered); } } } void answerWidget::on_btn_marked_clicked() { int nCount = ui->lw_aw_questionList->count(); for(int i = 0; i < nCount; ++i) { awQuestionNavigate *questionItem = dynamic_cast(ui->lw_aw_questionList->itemWidget(ui->lw_aw_questionList->item(i))); if(questionItem) { questionItem->setShowType(ITEM_SHOW_TYPE::ist_showMarked); } } } void answerWidget::on_btn_allNum_clicked() { on_btn_all_clicked(); } void answerWidget::on_btn_answeredNum_clicked() { on_btn_answered_clicked(); } void answerWidget::on_btn_unansweredNum_clicked() { on_btn_unanswered_clicked(); } void answerWidget::on_btn_markedNum_clicked() { on_btn_marked_clicked(); } void answerWidget::startCapture() { if(m_pinitTimer == nullptr) { m_pinitTimer = std::make_shared(); m_pinitTimer->setInterval(1000); connect(m_pinitTimer.get(), &QTimer::timeout, this, [&](){ m_pinitTimer->stop(); if(!m_cam.open(0)) { ShowMsg(QString::fromLocal8Bit("打开摄像头失败"), this); return; } int inWidth = ui->widget_aw_face->width(); m_cam.set(CV_CAP_PROP_FRAME_WIDTH, inWidth*3); int inHeight = ui->widget_aw_face->height(); m_cam.set(CV_CAP_PROP_FRAME_HEIGHT, inHeight*3); m_cam.set(CV_CAP_PROP_FPS, 5); m_pVideoTimer->start(); }); } g_inProcessFace->startFaceVerify(true); if(m_pVideoTimer == nullptr) { m_pVideoTimer = std::make_shared(); m_pVideoTimer->setInterval(200); m_nLastCaptureSecond = m_nLeftSeconds; connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){ cv::Mat frame; m_cam>>frame; if(frame.empty()) { qDebug()<<"widgetCameraTest frame is empty"; return; } if (g_inProcessFace != nullptr && m_nLastCaptureSecond - m_nLeftSeconds > g_appInfoPtr->m_oExamInfo.nSnapshotInterval) { m_nLastCaptureSecond = m_nLeftSeconds; g_inProcessFace->addImage(frame); } QImage img = CCommonTools::Mat2QImage(frame); ui->widget_aw_face->setAutoFillBackground(true); QPalette palette; palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_aw_face->width(), ui->widget_aw_face->height()))); ui->widget_aw_face->setPalette(palette); }); } m_pinitTimer->start(); } void answerWidget::stopCapture() { g_inProcessFace->startFaceVerify(false); m_pVideoTimer->stop(); if(m_cam.isOpened()) { m_cam.release(); } }