|
|
|
@ -1,10 +1,329 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<view>课程答题</view>
|
|
|
|
|
<view class="quiz-container">
|
|
|
|
|
<!-- 动态渲染题目 -->
|
|
|
|
|
<view :key="question.uuid" class="question">
|
|
|
|
|
<view >
|
|
|
|
|
<image :src="question.pic" mode="aspectFit" class="question-image" />
|
|
|
|
|
<!-- 单选题刘东阳 -->
|
|
|
|
|
<view v-if="question.tx==='单选题'">
|
|
|
|
|
<view class="grid-container">
|
|
|
|
|
<view v-for="(item, index) in zm.slice(0,question.xuexiangnum)" :key="index" class="grid-item">
|
|
|
|
|
<button
|
|
|
|
|
|
|
|
|
|
:style="{backgroundColor:dx===item?'blue':''}"
|
|
|
|
|
class="choose-button"
|
|
|
|
|
@click="dx_one(item)"
|
|
|
|
|
>
|
|
|
|
|
{{ item }}
|
|
|
|
|
</button>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="question.tx==='多选题'">
|
|
|
|
|
<view class="grid-container">
|
|
|
|
|
<view v-for="(item, index) in zm.slice(0,question.xuexiangnum)" :key="index" class="grid-item">
|
|
|
|
|
<button
|
|
|
|
|
|
|
|
|
|
:style="{backgroundColor:moredx.includes(item)?'blue':''}"
|
|
|
|
|
class="choose-button"
|
|
|
|
|
@click="moredx_one(item)"
|
|
|
|
|
>
|
|
|
|
|
{{ item }}
|
|
|
|
|
</button>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="question.tx==='判断题'">
|
|
|
|
|
<view class="grid-container-pd" >
|
|
|
|
|
<view :key="index" class="grid-item">
|
|
|
|
|
<button
|
|
|
|
|
|
|
|
|
|
:style="{backgroundColor:dx===item?'blue':''}"
|
|
|
|
|
class="choose-button"
|
|
|
|
|
@click="dx_one(item)"
|
|
|
|
|
>
|
|
|
|
|
√
|
|
|
|
|
</button>
|
|
|
|
|
</view>
|
|
|
|
|
<view :key="index" class="grid-item">
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
<view :key="index" class="grid-item">
|
|
|
|
|
<button
|
|
|
|
|
|
|
|
|
|
:style="{backgroundColor:dx===item?'blue':''}"
|
|
|
|
|
class="choose-button"
|
|
|
|
|
@click="dx_one(item)"
|
|
|
|
|
>
|
|
|
|
|
×
|
|
|
|
|
</button>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- 填空题 -->
|
|
|
|
|
<input v-if="question.type === 'fill'" v-model="userAnswers[question.id]" placeholder="请输入答案" />
|
|
|
|
|
|
|
|
|
|
<!-- 单选题 -->
|
|
|
|
|
<radio-group v-if="question.type === 'single'" :modelValue="userAnswers[question.id]"
|
|
|
|
|
@update:modelValue="handleRadioChange(question.id, $event)">
|
|
|
|
|
<label v-for="(option, i) in question.options" :key="i">
|
|
|
|
|
<radio :value="option.text[0]" />
|
|
|
|
|
<image v-if="option.image" :src="option.image" mode="aspectFit" class="option-image" />
|
|
|
|
|
<span v-else>{{ option.text }}</span>
|
|
|
|
|
</label>
|
|
|
|
|
</radio-group>
|
|
|
|
|
|
|
|
|
|
<!-- 多选题 -->
|
|
|
|
|
<checkbox-group v-if="question.type === 'multiple'" :modelValue="userAnswers[question.id]"
|
|
|
|
|
@update:modelValue="handleCheckboxChange(question.id, $event)">
|
|
|
|
|
<label v-for="(option, i) in question.options" :key="i">
|
|
|
|
|
<checkbox :value="option.text[0]" />
|
|
|
|
|
<image v-if="option.image" :src="option.image" mode="aspectFit" class="option-image" />
|
|
|
|
|
<span v-else>{{ option.text }}</span>
|
|
|
|
|
</label>
|
|
|
|
|
</checkbox-group>
|
|
|
|
|
|
|
|
|
|
<!-- 判断题 -->
|
|
|
|
|
<radio-group v-if="question.type === 'true-false'" :modelValue="userAnswers[question.id]"
|
|
|
|
|
@update:modelValue="handleRadioChange(question.id, $event)">
|
|
|
|
|
<label>
|
|
|
|
|
<radio value="true" /> 正确
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<radio value="false" /> 错误
|
|
|
|
|
</label>
|
|
|
|
|
</radio-group>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 控制按钮 -->
|
|
|
|
|
<view class="controls">
|
|
|
|
|
<button @click="prevQuestion">上一题</button>
|
|
|
|
|
<button @click="nextQuestion">下一题</button>
|
|
|
|
|
<button @click="submitAnswers" type="primary">提交答案</button>
|
|
|
|
|
<button @click="resetQuiz">重新答题</button>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 答案反馈 -->
|
|
|
|
|
<view v-if="showResult" class="result">
|
|
|
|
|
<text v-for="(res, key) in results" :key="key" :style="{ color: res ? 'green' : 'red' }">
|
|
|
|
|
第 {{ key + 1 }} 题:{{ res ? '✅ 正确' : '❌ 错误' }}
|
|
|
|
|
</text>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
const zm=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
|
|
|
|
|
const dx=ref('0');
|
|
|
|
|
const moredx=ref([])
|
|
|
|
|
const question=ref({
|
|
|
|
|
uuid: "e87ed72f-cecc-4ebd-9f08-34e24730797f",
|
|
|
|
|
px: 7,
|
|
|
|
|
kch: "202413501",
|
|
|
|
|
tea: "2024101",
|
|
|
|
|
title: "填空题APPPEERF",
|
|
|
|
|
infor: "{\"pic\":\"http://localhost:89/2024101/c2b9cfd7-1d46-45a5-bb02-ab701ab6aa84.png\",\"tk\":[{\"daan\":\"A\",\"print\":3},{\"daan\":\"B\",\"print\":4}],\"morechoose\":[\"A\"],\"onechoose\":\"A\",\"xuexiangnum\":4,\"zitimu\":[{\"pic\":\"http://localhost:89/tmbefore.png\",\"tk\":[{\"daan\":\"\",\"print\":1}],\"morechoose\":[\"A\"],\"onechoose\":\"A\",\"xuexiangnum\":4,\"title\":\"\"}],\"uuid\":\"e87ed72f-cecc-4ebd-9f08-34e24730797f\",\"tx\":\"填空题\",\"title\":\"填空题APPPEERF\"}",
|
|
|
|
|
kctime: "n8z1A1",
|
|
|
|
|
pic: "http://localhost:89/2024101/c2b9cfd7-1d46-45a5-bb02-ab701ab6aa84.png",
|
|
|
|
|
tk: [
|
|
|
|
|
{
|
|
|
|
|
daan: "A",
|
|
|
|
|
print: 3
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
daan: "B",
|
|
|
|
|
print: 4
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
morechoose: [
|
|
|
|
|
"A"
|
|
|
|
|
],
|
|
|
|
|
onechoose: "A",
|
|
|
|
|
xuexiangnum: 10,
|
|
|
|
|
zitimu: [
|
|
|
|
|
|
|
|
|
|
],
|
|
|
|
|
tx: "判断题"
|
|
|
|
|
})
|
|
|
|
|
// 题目数据(模拟从接口获取)
|
|
|
|
|
function dx_one(xx:string){
|
|
|
|
|
dx.value = xx
|
|
|
|
|
}
|
|
|
|
|
function moredx_one(xx:string){
|
|
|
|
|
if(moredx.value.includes(xx)){
|
|
|
|
|
moredx.value = moredx.value.filter(x=>x.value!==xx)
|
|
|
|
|
}else {
|
|
|
|
|
moredx.value.push(xx)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const quizData = [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
type: 'fill',
|
|
|
|
|
questionImage: '/static/student-course/bg.png',
|
|
|
|
|
answer: '前端界面'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
type: 'single',
|
|
|
|
|
questionImage: '/static/student-course/bg.png',
|
|
|
|
|
options: [
|
|
|
|
|
{ text: 'Vue Router', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'Vuex', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'Axios', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'Vue', image: '/static/student-course/bg.png' }
|
|
|
|
|
],
|
|
|
|
|
answer: 'C'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
type: 'multiple',
|
|
|
|
|
questionImage: '/static/student-course/bg.png',
|
|
|
|
|
options: [
|
|
|
|
|
{ text: 'ref', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'reactive', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'toRef', image: '/static/student-course/bg.png' },
|
|
|
|
|
{ text: 'defineProps', image: '/static/student-course/bg.png' }
|
|
|
|
|
],
|
|
|
|
|
answer: ['A', 'B', 'C']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 4,
|
|
|
|
|
type: 'true-false',
|
|
|
|
|
questionImage: '/static/student-course/bg.png',
|
|
|
|
|
answer: 'true'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const activeIndex = ref(0)
|
|
|
|
|
const showResult = ref(false)
|
|
|
|
|
|
|
|
|
|
// 用户答案:以题目 ID 为键存储答案
|
|
|
|
|
const userAnswers = ref<Record<number, any>>({})
|
|
|
|
|
|
|
|
|
|
const results = ref<boolean[]>([])
|
|
|
|
|
|
|
|
|
|
function handleRadioChange(id: number, value: string) {
|
|
|
|
|
userAnswers.value[id] = value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleCheckboxChange(id: number, value: string[]) {
|
|
|
|
|
userAnswers.value[id] = value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function prevQuestion() {
|
|
|
|
|
if (activeIndex.value > 0) activeIndex.value--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function nextQuestion() {
|
|
|
|
|
if (activeIndex.value < quizData.length - 1) activeIndex.value++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetQuiz() {
|
|
|
|
|
userAnswers.value = {}
|
|
|
|
|
showResult.value = false
|
|
|
|
|
activeIndex.value = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function submitAnswers() {
|
|
|
|
|
const answers = quizData.map((question) => {
|
|
|
|
|
const userAnswer = userAnswers.value[question.id]
|
|
|
|
|
const correctAnswer = question.answer
|
|
|
|
|
|
|
|
|
|
// 根据题型进行比较
|
|
|
|
|
if (question.type === 'fill') {
|
|
|
|
|
return userAnswer === correctAnswer
|
|
|
|
|
} else if (question.type === 'single') {
|
|
|
|
|
return userAnswer === correctAnswer
|
|
|
|
|
} else if (question.type === 'multiple') {
|
|
|
|
|
return (
|
|
|
|
|
Array.isArray(userAnswer) &&
|
|
|
|
|
Array.isArray(correctAnswer) &&
|
|
|
|
|
userAnswer.sort().join(',') === correctAnswer.sort().join(',')
|
|
|
|
|
)
|
|
|
|
|
} else if (question.type === 'true-false') {
|
|
|
|
|
return String(userAnswer) === String(correctAnswer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
results.value = answers
|
|
|
|
|
showResult.value = true
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
</style>
|
|
|
|
|
.controls {
|
|
|
|
|
margin-top: 30px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 15px;
|
|
|
|
|
/* 控制按钮之间间距 */
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls button {
|
|
|
|
|
padding: 12px 34px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
background-color: #4CAF50;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls button:hover {
|
|
|
|
|
background-color: #45a049;
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls button:active {
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls button[type="primary"] {
|
|
|
|
|
background-color: #2196F3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.controls button[type="primary"]:hover {
|
|
|
|
|
background-color: #1976D2;
|
|
|
|
|
}
|
|
|
|
|
.question-image{
|
|
|
|
|
margin-left: 35px;
|
|
|
|
|
}
|
|
|
|
|
.grid-container-pd
|
|
|
|
|
{
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
.grid-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
margin-left: 10vw;
|
|
|
|
|
}
|
|
|
|
|
.grid-item {
|
|
|
|
|
width: calc(25% - 10px); /* 每个项目宽度为25%,减去间距 */
|
|
|
|
|
|
|
|
|
|
margin: 5px; /* 项目之间的间距 */
|
|
|
|
|
|
|
|
|
|
box-sizing: border-box; /* 确保padding和border不会影响宽度 */
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.choose-button{
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
height: 18vw;
|
|
|
|
|
width: 18vw;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center; /* 水平居中 */
|
|
|
|
|
align-items: center; /* 垂直居中 */
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|