From f763e0bc88efa373ea0cedfdb1abbdc85046097b Mon Sep 17 00:00:00 2001
From: ZhangXianQiang <1135831638@qq.com>
Date: 星期三, 19 六月 2024 15:25:25 +0800
Subject: [PATCH] feat:考试音频题
---
src/components/ExamAudio/index.vue | 157 +++++++++++++++++++++++++++++++
src/components/ExamInfo/index.vue | 15 ++
src/views/exam/components/answer-main/answer-multiple/index.vue | 2
src/views/exam/components/answer-main/answer-audio/index.vue | 2
public/test.mp3 | 0
src/store/modules/exam.js | 70 +++++++++++++
components.d.ts | 1
src/views/exam/components/answer-main/answer-single/index.vue | 2
src/views/exam/index.vue | 6 +
9 files changed, 245 insertions(+), 10 deletions(-)
diff --git a/components.d.ts b/components.d.ts
index 8742b82..29dd682 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -29,6 +29,7 @@
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
+ ExamAudio: typeof import('./src/components/ExamAudio/index.vue')['default']
ExamInfo: typeof import('./src/components/ExamInfo/index.vue')['default']
ExamInfoDialog: typeof import('./src/components/ExamInfoDialog/index.vue')['default']
Header: typeof import('./src/components/Header/index.vue')['default']
diff --git a/public/test.mp3 b/public/test.mp3
new file mode 100644
index 0000000..7b0f622
--- /dev/null
+++ b/public/test.mp3
Binary files differ
diff --git a/src/components/ExamAudio/index.vue b/src/components/ExamAudio/index.vue
new file mode 100644
index 0000000..c96e17d
--- /dev/null
+++ b/src/components/ExamAudio/index.vue
@@ -0,0 +1,157 @@
+<template>
+ <div class="audio-container">
+ <div class="audio_wrap_content">
+ <audio ref="audioRef" @play="playFunc" @pause="pauseFunc" @timeupdate="timeupdateFunc"
+ @loadedmetadata="onLoadedmetadata" @ended="handleEnd">
+ <source :src="audioSrc" />
+ </audio>
+ <div class="cudio_control_content">
+ <el-icon :size="32" color="#3680fa" @click="startPlayOrPause" class="cursor-pointer">
+ <VideoPlay v-show="!audio.playing" />
+ <VideoPause v-show="audio.playing" />
+ </el-icon>
+ <div class="slider">
+ <span>{{ formattedCurrentTime }}</span>
+ <div @mousedown="audio.dragState = true" @mouseup="audio.dragState = false"
+ @mouseleave="audio.dragState = false"><el-slider v-model="sliderTime" size="small" :max="audio.maxTime"
+ :show-tooltip="false" @change="onChange"></el-slider></div>
+ <span>{{ formattedMaxTime }}</span>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</template>
+
+<script setup>
+import { ref, computed, onBeforeUnmount } from 'vue';
+import { VideoPlay, VideoPause } from '@element-plus/icons-vue';
+
+const props = defineProps({
+ audioSrc: {
+ type: String,
+ required: true,
+ default: ''
+ }
+});
+const sliderTime = ref(0);
+const audioRef = ref(null);
+
+const audio = ref({
+ maxTime: 0,
+ currentTime: 0,
+ playing: false,
+ dragState: false
+});
+
+
+const formatTime = (second) => {
+ let m = parseInt(second / 60);
+ let s = parseInt(second % 60);
+ let time = "";
+ if (second == 0) {
+ return "0'00''";
+ }
+ if (m == 0) {
+ if (s >= 10) {
+ time = "0'" + s + "''";
+ } else {
+ time = "0'0" + s + "''";
+ }
+ } else {
+ if (s >= 10) {
+ time = m + "'" + s + "''";
+ } else {
+ time = m + "'0" + s + "''";
+ }
+ }
+ return time;
+};
+
+const formattedCurrentTime = computed(() => {
+ return formatTime(audio.value.currentTime);
+});
+const formattedMaxTime = computed(() => {
+ return formatTime(audio.value.maxTime);
+});
+
+const play = () => {
+ audioRef.value.play();
+};
+const pause = () => {
+ audioRef.value.pause();
+};
+const playFunc = () => {
+ audio.value.playing = true;
+};
+const pauseFunc = () => {
+ audio.value.playing = false;
+};
+const handleEnd = () => {
+ sliderTime.value = 0;
+ audio.value.playing = false;
+ audio.value.currentTime = 0;
+};
+const timeupdateFunc = (res) => {
+ if (!audio.value.dragState) {
+ audio.value.currentTime = res.target.currentTime;
+ sliderTime.value = res.target.currentTime;
+ }
+};
+const onLoadedmetadata = (res) => {
+ audio.value.maxTime = parseInt(res.target.duration);
+};
+const startPlayOrPause = () => {
+ audio.value.playing ? pause() : play();
+};
+const onChange = (value) => {
+ audioRef.value.currentTime = value;
+};
+
+onBeforeUnmount(() => {
+ pause();
+});
+
+</script>
+
+<style lang="scss" scoped>
+.audio-container {
+ width: 400px;
+ border: 1px solid #3680fa;
+ height: 50px;
+ border-radius: 50px;
+}
+
+.audio_wrap_content {
+ height: 100%;
+}
+
+.cudio_control_content {
+ margin: 0 auto;
+ width: 90%;
+ height: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .slider {
+ flex: 1;
+ width: 100%;
+ display: flex;
+ align-items: center;
+
+ }
+
+ .slider div {
+ flex: 1;
+ }
+
+ .slider span {
+ margin: 0 15px;
+ font-size: 12px;
+ color: rgba(34, 34, 34, 0.5);
+ }
+
+
+}
+</style>
\ No newline at end of file
diff --git a/src/components/ExamInfo/index.vue b/src/components/ExamInfo/index.vue
index 2b63fd1..7adb980 100644
--- a/src/components/ExamInfo/index.vue
+++ b/src/components/ExamInfo/index.vue
@@ -1,8 +1,13 @@
<template>
<div class="info-container w-full">
<div class="exam-title break-all mb-4 text-base text-gray-700">
- {{ title }}
+ 绗瑊{questionIndex + 1}}棰�: {{ activeQuestion.title }}
</div>
+
+ <div class="audio-container" v-if="activeQuestion.audioFile">
+ <ExamAudio :audioSrc="activeQuestion.audioFile"></ExamAudio>
+ </div>
+
<div class="img-container flex">
<div class="img-item">
<img src="@/assets/test.png" class="info-img" alt="">
@@ -12,13 +17,15 @@
</template>
<script setup>
+import ExamAudio from '@/components/ExamAudio/index.vue';
+
const props = defineProps({
questionIndex: {
type: Number,
required: true
},
- title: {
- type: String,
+ activeQuestion: {
+ type: Object,
required: true
}
})
@@ -27,6 +34,6 @@
<style lang="scss" scoped>
.info-img {
max-height: 250px;
- margin: 20px 0;
+ margin: 20px 10px;
}
</style>
\ No newline at end of file
diff --git a/src/store/modules/exam.js b/src/store/modules/exam.js
index edafdef..d159b47 100644
--- a/src/store/modules/exam.js
+++ b/src/store/modules/exam.js
@@ -14,6 +14,7 @@
const examType = ref({
1: '鍗曢�夐',
2: '澶氶�夐',
+ 3: '闊抽棰�'
});
const currentType = ref(1);
@@ -205,7 +206,72 @@
"difficult": 5
}
]
- }
+ },
+ {
+ questionType: 3,
+ questionList: [
+ {
+ "id": null,
+ "questionType": 1,
+ "gradeLevel": null,
+ "subjectId": 2,
+ "title": "娴嬭瘯闊抽1",
+ "audioFile": '/test.mp3',
+ "items": [
+ {
+ "prefix": "A",
+ "content": "1"
+ },
+ {
+ "prefix": "B",
+ "content": "2"
+ },
+ {
+ "prefix": "C",
+ "content": "3"
+ },
+ {
+ "prefix": "D",
+ "content": "4"
+ }
+ ],
+ "analyze": "闂皬鏈嬪弸",
+ "correct": "",
+ "score": "3",
+ "difficult": 5
+ },
+ {
+ "id": null,
+ "questionType": 1,
+ "gradeLevel": null,
+ "subjectId": 2,
+ "title": "娴嬭瘯闊抽2",
+ "audioFile": '/test.mp3',
+ "items": [
+ {
+ "prefix": "A",
+ "content": "1"
+ },
+ {
+ "prefix": "B",
+ "content": "2"
+ },
+ {
+ "prefix": "C",
+ "content": "3"
+ },
+ {
+ "prefix": "D",
+ "content": "4"
+ }
+ ],
+ "analyze": "闂皬鏈嬪弸",
+ "correct": "",
+ "score": "3",
+ "difficult": 5
+ }
+ ]
+ },
]);
const getActiveQuestion = computed(() => {
@@ -248,7 +314,7 @@
const setProgress = (progress) => {
answerProgress.value = progress;
- }
+ };
return {
diff --git a/src/views/exam/components/answer-main/answer-audio/index.vue b/src/views/exam/components/answer-main/answer-audio/index.vue
index b58b59f..705d1d0 100644
--- a/src/views/exam/components/answer-main/answer-audio/index.vue
+++ b/src/views/exam/components/answer-main/answer-audio/index.vue
@@ -1,7 +1,7 @@
<template>
<div class="answer-container w-full h-full">
<el-scrollbar>
- <ExamInfo class="mb-5" :questionIndex="currentIndex" :title="activeQuestion.title"></ExamInfo>
+ <ExamInfo class="mb-5" :questionIndex="currentIndex" :activeQuestion="activeQuestion"></ExamInfo>
<div class="answer-content">
<div class="answer-item flex" v-for="item, index in activeQuestion.items" @click="answerClick(item)"
diff --git a/src/views/exam/components/answer-main/answer-multiple/index.vue b/src/views/exam/components/answer-main/answer-multiple/index.vue
index e925454..b127aff 100644
--- a/src/views/exam/components/answer-main/answer-multiple/index.vue
+++ b/src/views/exam/components/answer-main/answer-multiple/index.vue
@@ -1,7 +1,7 @@
<template>
<div class="answer-container w-full h-full">
<el-scrollbar>
- <ExamInfo class="mb-5" :questionIndex="currentIndex" :title="activeQuestion.title"></ExamInfo>
+ <ExamInfo class="mb-5" :questionIndex="currentIndex" :activeQuestion="activeQuestion"></ExamInfo>
<div class="answer-content">
<div class="answer-item flex" v-for="item, index in activeQuestion.items" @click="answerClick(item)"
diff --git a/src/views/exam/components/answer-main/answer-single/index.vue b/src/views/exam/components/answer-main/answer-single/index.vue
index b58b59f..705d1d0 100644
--- a/src/views/exam/components/answer-main/answer-single/index.vue
+++ b/src/views/exam/components/answer-main/answer-single/index.vue
@@ -1,7 +1,7 @@
<template>
<div class="answer-container w-full h-full">
<el-scrollbar>
- <ExamInfo class="mb-5" :questionIndex="currentIndex" :title="activeQuestion.title"></ExamInfo>
+ <ExamInfo class="mb-5" :questionIndex="currentIndex" :activeQuestion="activeQuestion"></ExamInfo>
<div class="answer-content">
<div class="answer-item flex" v-for="item, index in activeQuestion.items" @click="answerClick(item)"
diff --git a/src/views/exam/index.vue b/src/views/exam/index.vue
index 585a0ec..090e41e 100644
--- a/src/views/exam/index.vue
+++ b/src/views/exam/index.vue
@@ -103,9 +103,12 @@
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 AnswerAudio from './components/answer-main/answer-audio/index.vue';
+
import { useExamStore } from '@/store/index.js';
import { useRouter } from 'vue-router';
@@ -117,6 +120,7 @@
const typeComponent = {
1: AnswerSingle,
2: AnswerMultiple,
+ 3: AnswerAudio,
};
const dialogVisible = ref(false);
--
Gitblit v1.8.0