<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>在线考试系统</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/element-plus/2.3.14/index.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.4/vue.global.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/element-plus/2.3.14/index.full.js"></script><style>[v-cloak] { display: none; }body {margin: 0;font-family: system-ui, -apple-system, sans-serif;background-color: }.container {max-width: 1200px;margin: 0 auto;padding: 20px;}.exam-page {display: flex;gap: 20px;}.main-content {flex: 3;}.sidebar {flex: 1;}.question-section {margin-bottom: 20px;}.question-section-title {margin: 15px 0 10px 0;display: flex;align-items: center;gap: 10px;}.question-list {display: grid;grid-template-columns: repeat(4, 1fr);gap: 10px;}.question-item {aspect-ratio: 1;border: 1px solid display: flex;align-items: center;justify-content: center;cursor: pointer;border-radius: 4px;position: relative;min-height: 40px;}.question-item.answered {background-color: border-color: }.question-item.current {border: 2px solid }.question-item-content {display: flex;flex-direction: column;align-items: center;justify-content: center;width: 100%;height: 100%;padding: 5px;}.question-item-number {font-size: 16px;font-weight: bold;}.exam-header {margin-bottom: 20px;}.question-type-tag {margin-left: 10px;}.exam-navigation {margin-top: 20px;display: flex;justify-content: space-between;}.answer-card-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 15px;}.question-content {margin-bottom: 20px;}.el-radio, .el-checkbox {margin-bottom: 12px;width: 100%;}.el-radio.is-bordered, .el-checkbox.is-bordered {padding: 12px 20px;}</style>
</head>
<body>
<div id="app" v-cloak><!-- 开始考试页面 --><div v-if="showStart" class="container"><el-card style="max-width: 500px; margin: 100px auto; text-align: center;"><template <h2>在线考试系统</h2></template><p>考试时长:90分钟</p><p>共{{questions.length}}道题目</p><el-button type="primary" @click="startExam">开始考试</el-button></el-card></div><!-- 考试页面 --><div v-if="showExam" class="container"><div class="exam-page"><!-- 左侧主要内容区 --><div class="main-content"><div class="exam-header"><el-row justify="space-between" align="middle"><el-col :span="12"><h2>在线考试系统</h2></el-col><el-col :span="12" style="text-align: right;"><el-tag size="large" type="warning">剩余时间:{{ formatTime(timeLeft) }}</el-tag></el-col></el-row></div><el-card><template <div class="card-header"><span>第 {{ currentQuestion + 1 }} 题</span><el-tag:type="getQuestionTypeInfo(questions[currentQuestion].type).tagType"class="question-type-tag">{{ getQuestionTypeInfo(questions[currentQuestion].type).text }}</el-tag></div></template><div class="question-content"><p>{{ questions[currentQuestion].content }}</p><!-- 单选题 --><template v-if="questions[currentQuestion].type === 'single'"><el-radio-group v-model="answers[questions[currentQuestion].id]"><el-radiov-for="option in questions[currentQuestion].options":key="option.id":label="option.id"border>{{ option.id }}. {{ option.text }}</el-radio></el-radio-group></template><!-- 多选题 --><template v-if="questions[currentQuestion].type === 'multiple'"><el-checkbox-group v-model="answers[questions[currentQuestion].id]"><el-checkboxv-for="option in questions[currentQuestion].options":key="option.id":label="option.id"border>{{ option.id }}. {{ option.text }}</el-checkbox></el-checkbox-group></template><!-- 填空题和问答题 --><template v-if="['fillblank', 'comprehensive'].includes(questions[currentQuestion].type)"><el-inputv-model="answers[questions[currentQuestion].id]"type="textarea":rows="6"placeholder="请输入你的答案..."/></template></div><div class="exam-navigation"><el-button@click="prevQuestion":disabled="currentQuestion === 0">上一题</el-button><el-buttontype="primary"@click="nextQuestion":disabled="currentQuestion === questions.length - 1">下一题</el-button></div></el-card></div><!-- 右侧答题卡 --><div class="sidebar"><el-card><template <div class="answer-card-header"><span>答题卡</span><el-progress:percentage="completionRate":format="format => `${answeredCount}/${questions.length}`"style="width: 100px;"/></div></template><!-- 按题型分组显示题目 --><divv-for="(groupQuestions, type) in questionsByType":key="type"class="question-section"><div class="question-section-title"><el-tag:type="getQuestionTypeInfo(type).tagType"size="small">{{getQuestionTypeInfo(type).text}}</el-tag><span class="question-count">{{groupQuestions.length}}题</span></div><div class="question-list"><divv-for="q in groupQuestions":key="q.id"class="question-item":class="{'answered': isAnswered(q.id),'current': currentQuestion === questions.findIndex(item => item.id === q.id)}"@click="goToQuestion(questions.findIndex(item => item.id === q.id))"><div class="question-item-content"><span class="question-item-number">{{q.id}}</span></div></div></div></div><el-buttontype="primary"style="width: 100%; margin-top: 20px;"@click="confirmSubmit">交卷</el-button></el-card></div></div></div><!-- 结果页面 --><div v-if="showResult" class="container"><el-card style="max-width: 500px; margin: 100px auto; text-align: center;"><template <h2>考试已结束</h2></template><p>你已完成所有题目</p><p>答题完成率:{{ completionRate }}%</p><el-button type="primary" @click="restartExam">重新开始</el-button></el-card></div>
</div><script>const { createApp, ref, computed } = Vue;const app = createApp({setup() {const questions = [{id: 1,type: 'single',content: '以下哪个是JavaScript的基本数据类型?',options: [{ id: 'A', text: 'Array' },{ id: 'B', text: 'String' },{ id: 'C', text: 'Object' },{ id: 'D', text: 'Function' }]},{id: 2,type: 'multiple',content: '以下哪些是React的核心特性? (多选)',options: [{ id: 'A', text: '单向数据流' },{ id: 'B', text: '虚拟DOM' },{ id: 'C', text: '组件化' },{ id: 'D', text: 'JSX语法' }]},{id: 3,type: 'fillblank',content: '请补充完整: React中用于处理副作用的钩子是__________。'},{id: 4,type: 'comprehensive',content: '请解释React中的状态管理,并比较Redux和Context API的异同。'}];const showStart = ref(true);const showExam = ref(false);const showResult = ref(false);const currentQuestion = ref(0);const answers = ref({});const timeLeft = ref(90 * 60); // 90分钟let timer = null;// 开始考试const startExam = () => {showStart.value = false;showExam.value = true;startTimer();};// 计时器const startTimer = () => {timer = setInterval(() => {timeLeft.value--;if (timeLeft.value <= 0) {submitExam();}}, 1000);};// 格式化时间const formatTime = (seconds) => {const minutes = Math.floor(seconds / 60);const remainingSeconds = seconds % 60;return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;};// 获取题型信息const getQuestionTypeInfo = (type) => {const typeMap = {single: { text: '单选题', tagType: 'info' },multiple: { text: '多选题', tagType: 'success' },fillblank: { text: '填空题', tagType: 'warning' },comprehensive: { text: '综合题', tagType: 'danger' }};return typeMap[type] || { text: '其他', tagType: 'info' };};// 导航方法const prevQuestion = () => {if (currentQuestion.value > 0) {currentQuestion.value--;}};const nextQuestion = () => {if (currentQuestion.value < questions.length - 1) {currentQuestion.value++;}};const goToQuestion = (index) => {currentQuestion.value = index;};// 判断题目是否已答const isAnswered = (questionId) => {const answer = answers.value[questionId];if (Array.isArray(answer)) {return answer.length > 0;}return !!answer;};// 计算完成率和已答题数const answeredCount = computed(() => {return Object.values(answers.value).filter(answer => {if (Array.isArray(answer)) {return answer.length > 0;}return !!answer;}).length;});const completionRate = computed(() => {return Math.round((answeredCount.value / questions.length) * 100);});// 按题型分组的计算属性const questionsByType = computed(() => {return questions.reduce((acc, question) => {if (!acc[question.type]) {acc[question.type] = [];}acc[question.type].push(question);return acc;}, {});});// 提交考试const confirmSubmit = () => {ElementPlus.ElMessageBox.confirm('确定要交卷吗?','提示',{confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {submitExam();}).catch(() => {});};const submitExam = () => {clearInterval(timer);showExam.value = false;showResult.value = true;};// 重新开始const restartExam = () => {showResult.value = false;showStart.value = true;currentQuestion.value = 0;answers.value = {};timeLeft.value = 90 * 60;};return {questions,showStart,showExam,showResult,currentQuestion,answers,timeLeft,startExam,formatTime,getQuestionTypeInfo,prevQuestion,nextQuestion,goToQuestion,isAnswered,answeredCount,completionRate,confirmSubmit,restartExam,questionsByType};}});app.use(ElementPlus);app.mount('#app');
</script>
</body>
</html>