ZhangXianQiang
2024-07-05 98f494cf633e3acf5c20f3e9de0d708f2a6c2045
src/views/exam/index.vue
@@ -5,9 +5,9 @@
      <div class="exam-wrapper container mx-auto h-full flex flex-col">
        <div class="exam-header flex items-center mt-12 mb-10">
          <div class="title-container text-3xl font-semibold text-white mr-8">
            测试测试测试
            {{ examInfo.examName }}
          </div>
          <AnswerTime></AnswerTime>
          <AnswerTime @timeOut="timeOut"></AnswerTime>
          <div class="return-container grow flex justify-end">
            <el-button type="danger" size="large" circle @click="closeClick">
@@ -40,7 +40,7 @@
              </div>
              <div class="submit-wrapper">
                <el-button type="primary" class="submit-button">提交试卷</el-button>
                <el-button type="primary" class="submit-button" @click="submitExamHandle">提交试卷</el-button>
              </div>
            </div>
@@ -50,7 +50,9 @@
          <div class="answer-wrapper answer-right grow shadow-xl p-4">
            <div class="wrapper h-full flex flex-col">
              <div class="title-wrapper w-full flex mb-5">
                <div class="title text-xl font-semibold ">单选题 (3分)</div>
                <div class="title text-xl font-semibold ">{{ examType[currentType] }} ({{
                  examStore.getActiveQuestion.questionScore }}分)
                </div>
              </div>
              <div class="main-wrapper w-full grow relative my-5">
@@ -79,58 +81,120 @@
    <!-- 退出考试提示弹窗 -->
    <el-dialog v-model="dialogVisible" title="注意" width="500">
    <el-dialog v-model="quitDialog" title="注意" width="500">
      <div class="dialog-container">
        <p>请确认是否退出当前考试</p>
        <p>当前考试试卷会自动提交,后续将无法继续作答</p>
        <p>当前试卷会自动提交,后续将无法继续作答</p>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmCancel">
            确定
          <el-button @click="quitDialog = false">继续作答</el-button>
          <el-button type="danger" @click="confirmQuit">
            确定退出
          </el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 交卷提示弹窗 -->
    <el-dialog v-model="submitDialog" title="确认交卷?" width="500">
      <div class="dialog-container">
        <p>请确认是否提交试卷</p>
        <p>一旦交卷将无法继续作答或修改答案</p>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="submitDialog = false">继续作答</el-button>
          <el-button type="primary" @click="confirmSubmit">
            确认提交
          </el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 考试时间弹窗 -->
    <el-dialog v-model="timeDialog" align-center width="500" :close-on-click-modal="false"
      :close-on-press-escape="false" :show-close="false">
      <div class="dialog-container flex flex-col items-center">
        <div class="icon-container">
          <el-icon :size="50" color="#3680fa">
            <Timer />
          </el-icon>
        </div>
        <div class="dialog-info">
          考试结束,系统自动收卷中.......
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, watchEffect } from 'vue';
import { ref, watchEffect, watch, onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { Close } from '@element-plus/icons-vue';
import { Close, Timer } from '@element-plus/icons-vue';
import AnswerTag from './components/answer-tag/index.vue';
import AnswerProgress from './components/answer-progress/index.vue';
import AnswerSheet from './components/answer-sheet/index.vue';
import AnswerTime from './components/answer-time/index.vue';
import AnswerSingle from './components/answer-main/answer-single/index.vue';
import AnswerMultiple from './components/answer-main/answer-multiple/index.vue';
import AnswerTime from './components/answer-time/index.vue';
import { useExamStore } from '@/store/index.js';
import AnswerAudio from './components/answer-main/answer-audio/index.vue';
import AnswerFill from './components/answer-main/answer-fill/index.vue';
import AnswerDetermine from './components/answer-main/answer-determine/index.vue';
import AnswerShort from './components/answer-main/answer-short/index.vue';
import AnswerCount from './components/answer-main/answer-count/index.vue';
import { useExamStore, useUserStore } from '@/store/index.js';
import { useRouter } from 'vue-router';
import { submitExam } from '@/api/modules/exam.js';
import useWebScoket from '@/hooks/useWebScoket.js';
const router = useRouter();
const examStore = useExamStore();
const { currentType, currentIndex, examDetail } = storeToRefs(examStore);
const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);
const { currentType, currentIndex, examDetail, examType, examInfo } = storeToRefs(examStore);
const typeComponent = {
  1: AnswerSingle,
  2: AnswerMultiple,
  3: AnswerDetermine,
  4: AnswerFill,
  5: AnswerShort,
  6: AnswerAudio,
  7: AnswerCount,
  8: AnswerShort,
};
const dialogVisible = ref(false);
const quitDialog = ref(false);
const submitDialog = ref(false);
const timeDialog = ref(false);
const { status, message, error, connect, disconnect, sendMessage } = useWebScoket({
  url: 'ws://192.168.3.64:8000/websocket/' + userInfo.value.id,
  heartBeatData: 'ping'
});
// 上一题
const prevQuestion = () => {
  currentIndex.value--;
  checkList();
};
// 下一题
const nextQuestion = () => {
  currentIndex.value++;
  checkList();
};
// 查询题目
const checkList = () => {
  let tempIndex = 0;
  const typeQuestion = examDetail.value.find((typeItem, index) => {
@@ -162,40 +226,78 @@
        currentIndex.value = 0;
      }
    }
    // findQuestion(currentType.value, currentIndex.value);
  }
};
const findQuestion = (type, index) => {
  const typeQuestion = examDetail.value.find(typeItem => typeItem.questionType === type);
  if (typeQuestion) {
    const question = typeQuestion.questionList[index];
    if (question) {
      examStore.setActiveQuestion(question);
    }
  }
};
// 退出考试
const closeClick = () => {
  dialogVisible.value = true;
  quitDialog.value = true;
};
const confirmCancel = () => {
  dialogVisible.value = false;
  router.back();
const confirmQuit = () => {
  timeOut();
};
// 交卷
const submitExamHandle = () => {
  submitDialog.value = true;
};
const confirmSubmit = () => {
  timeOut();
};
const resetAllDialog = () => {
  quitDialog.value = false;
  submitDialog.value = false;
};
// 时间结束
const timeOut = () => {
  const temp = {
    ...examInfo.value,
    titleList: examDetail.value
  };
  timeDialog.value = true;
  resetAllDialog();
  disconnect();
  submitExam(temp).then(res => {
    returnBack();
  }).catch(() => {
    returnBack();
  });
};
const returnBack = () => {
  setTimeout(() => {
    router.back();
  }, 2000);
};
watchEffect(() => {
  let progress = 0;
  examDetail.value.forEach(item => {
    item.questionList.forEach(question => {
      if(question.correct) {
      if (question.answer || (Array.isArray(question.answerList) && question.answerList.length)) {
        progress += 1;
      }
    });
  });
  examStore.setProgress(progress);
});
watch(() => message.value, (msg) => {
  console.log(msg);
});
// -----------------------------------生命周期
onMounted(() => {
  // 连接webscoket
  connect();
});
</script>
@@ -236,7 +338,7 @@
}
.answer-left {
  width: 340px;
  width: 370px;
}
.submit-button,
@@ -248,4 +350,15 @@
.tool-button {
  margin: 0 20px;
}
.icon-container {
  width: 70px;
  height: 70px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba($color: #3680fa, $alpha: 0.2);
  margin-bottom: 20px;
}
</style>