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