Commit c9c5ae56 authored by liujiangnan's avatar liujiangnan

feat

parent 32916f24
/* 基于视口单位的等比例缩放系统 */
/* 设计基准:1920x1080 桌面横屏 */
/* 全局样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#app {
margin: 0 auto;
border-radius: calc(15 * 100vw / 1920);
box-shadow: 0 calc(10 * 100vw / 1920) calc(30 * 100vw / 1920) rgba(0, 0, 0, 0.2);
body {
min-height: 100vh;
overflow: hidden;
}
#app {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.question-container {
position: absolute;
top: calc(10 * 100vw / 1920);
left: calc(10 * 100vw / 1920);
bottom: calc(10 * 100vw / 1920);
right: calc(10 * 100vw / 1920);
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
}
/* 题干部分样式 */
/* 题干部分样式 - 占据屏幕上50% */
.question-section {
margin-bottom: calc(30 * 100vw / 1920);
padding: calc(25 * 100vw / 1920);
height: 50vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
position: relative;
}
.question-content {
background: rgba(0, 0, 0, 0.2);
border: 2px solid white;
border-radius: 12px;
padding: 30px;
max-width: 80vw;
width: fit-content;
text-align: center;
color: white;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.question-image {
text-align: center;
margin-bottom: calc(20 * 100vw / 1920);
order: -1; /* 图片在最上面 */
}
.question-image img {
max-width: 100%;
max-height: calc(250 * 100vw / 1920);
border-radius: calc(10 * 100vw / 1920);
box-shadow: 0 calc(4 * 100vw / 1920) calc(12 * 100vw / 1920) rgba(0, 0, 0, 0.1);
max-height: 200px;
border-radius: 8px;
object-fit: contain;
}
.question-audio {
margin-bottom: calc(20 * 100vw / 1920);
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.audio-icon {
width: 24px;
height: 24px;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
gap: calc(15 * 100vw / 1920);
cursor: pointer;
transition: all 0.3s ease;
flex-shrink: 0;
}
.audio-icon:hover {
background: #409EFF;
color: white;
}
.audio-icon i {
font-size: 12px;
color: #333;
}
.question-audio .audio-info {
color: #606266;
font-size: calc(14 * 100vw / 1920);
.audio-icon:hover i {
color: white;
}
.question-text {
font-size: 22px;
line-height: 1.6;
word-wrap: break-word;
max-width: 100%;
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
justify-content: center;
}
.question-text h3 {
margin: 0;
color: #303133;
font-size: calc(20 * 100vw / 1920);
font-size: 22px;
line-height: 1.6;
font-weight: 600;
word-wrap: break-word;
max-width: 100%;
}
/* 选项部分样式 */
/* 选项部分样式 - 占据屏幕下50% */
.options-section {
margin-bottom: calc(30 * 100vw / 1920);
height: 50vh;
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.options-grid {
display: flex;
gap: 20px;
max-width: 90vw;
flex-wrap: wrap;
gap: calc(15 * 100vw / 1920);
justify-content: center;
}
/* 选项卡片基础样式 */
.option-item {
flex: 0 0 calc(300 * 100vw / 1920);
max-width: calc(300 * 100vw / 1920);
min-height: calc(200 * 100vw / 1920);
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 0;
padding: calc(20 * 100vw / 1920);
border: calc(2 * 100vw / 1920) solid #e4e7ed;
border-radius: calc(10 * 100vw / 1920);
background: rgba(0, 0, 0, 0.2);
border: 2px solid white;
border-radius: 12px;
padding: 30px;
cursor: pointer;
transition: all 0.3s ease;
background: white;
text-align: center;
color: white;
display: flex;
align-items: center;
gap: 15px;
min-width: 200px;
max-width: 300px;
position: relative; /* 为绝对定位的子元素提供参考 */
}
.option-item:hover {
border-color: #409EFF;
box-shadow: 0 calc(4 * 100vw / 1920) calc(12 * 100vw / 1920) rgba(64, 158, 255, 0.15);
transform: translateY(calc(-2 * 100vw / 1920));
background: rgba(64, 158, 255, 0.2);
}
.option-item.selected {
border-color: #409EFF;
background: #f0f9ff;
}
.option-item.selected .option-selected {
color: #409EFF;
font-size: calc(24 * 100vw / 1920);
border-color: #67C23A;
background: rgba(103, 194, 58, 0.2);
}
/* 选项内容布局 */
.option-content {
flex: 1;
display: flex;
flex-direction: column;
gap: calc(10 * 100vw / 1920);
width: 100%;
align-items: center;
gap: 15px;
width: 100%;
}
.option-image {
text-align: center;
margin-bottom: calc(10 * 100vw / 1920);
}
.option-image img {
max-width: calc(120 * 100vw / 1920);
max-height: calc(120 * 100vw / 1920);
border-radius: calc(6 * 100vw / 1920);
object-fit: cover;
.option-audio {
flex-shrink: 0;
}
.option-audio {
.option-text {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: calc(8 * 100vw / 1920);
margin-bottom: calc(10 * 100vw / 1920);
}
.option-audio .audio-info {
color: #606266;
font-size: calc(12 * 100vw / 1920);
gap: 8px;
text-align: center;
width: 100%;
}
.option-text {
.option-text-content {
font-size: 22px;
line-height: 1.4;
color: white;
display: flex;
flex-direction: column;
align-items: center;
gap: calc(8 * 100vw / 1920);
gap: 8px;
justify-content: flex-start;
text-align: left;
width: 100%;
}
.option-label {
position: absolute;
top: -10px;
left: -10px;
font-weight: bold;
color: #409EFF;
font-size: calc(18 * 100vw / 1920);
margin-bottom: calc(5 * 100vw / 1920);
font-size: 22px;
color: white;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.option-text-content {
color: #303133;
font-size: calc(16 * 100vw / 1920);
line-height: 1.5;
text-align: center;
word-wrap: break-word;
.option-image {
flex-shrink: 0;
order: -1; /* 图片在最上面 */
}
.option-image img {
max-width: 80px;
max-height: 80px;
border-radius: 8px;
object-fit: cover;
}
/* 有图片时的横向布局 */
.options-grid.has-images {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.option-status {
margin-top: calc(10 * 100vw / 1920);
.options-grid.has-images .option-item {
flex: 0 0 auto;
min-width: 250px;
}
.option-selected {
color: #409EFF;
font-size: calc(24 * 100vw / 1920);
/* 纯文本时的两列布局 */
.options-grid.text-only {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
width: 100%;
}
/* 提交按钮部分 */
.options-grid.text-only .option-item {
width: 100%;
max-width: none;
}
/* 提交按钮 */
.submit-section {
position: absolute;
right: calc(30 * 100vw / 1920);
bottom: calc(30 * 100vw / 1920);
position: fixed;
bottom: 60px;
right: 60px;
z-index: 1000;
}
.submit-section .el-button {
......@@ -179,6 +261,18 @@
border-radius: calc(8 * 100vw / 1920);
}
.submit-section .el-button:hover {
background: rgba(103, 194, 58, 1);
transform: translateY(-2px);
}
.submit-section .el-button:disabled {
background: rgba(0, 0, 0, 0.3);
border-color: rgba(255, 255, 255, 0.3);
cursor: not-allowed;
transform: none;
}
/* 庆祝动画弹窗 */
.celebration-modal {
position: fixed;
......@@ -186,7 +280,7 @@
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
......@@ -195,37 +289,38 @@
}
.celebration-content {
background: white;
padding: calc(40 * 100vw / 1920);
border-radius: calc(20 * 100vw / 1920);
background: rgba(0, 0, 0, 0.9);
border: 2px solid #67C23A;
border-radius: 20px;
padding: 40px;
text-align: center;
box-shadow: 0 calc(10 * 100vw / 1920) calc(30 * 100vw / 1920) rgba(0, 0, 0, 0.3);
color: white;
animation: bounceIn 0.6s ease-out;
position: relative;
z-index: 10000;
}
.celebration-icon {
font-size: calc(80 * 100vw / 1920);
margin-bottom: calc(20 * 100vw / 1920);
font-size: 80px;
margin-bottom: 20px;
animation: bounce 1s infinite;
}
.celebration-text {
font-size: calc(32 * 100vw / 1920);
font-size: 32px;
font-weight: bold;
color: #67c23a;
margin-bottom: calc(20 * 100vw / 1920);
color: #67C23A;
margin-bottom: 20px;
}
.celebration-stars {
display: flex;
justify-content: center;
gap: calc(10 * 100vw / 1920);
gap: 10px;
}
.star {
font-size: calc(24 * 100vw / 1920);
font-size: 24px;
animation: twinkle 1.5s infinite;
}
......@@ -244,7 +339,7 @@
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
......@@ -253,36 +348,37 @@
}
.error-content {
background: white;
padding: calc(40 * 100vw / 1920);
border-radius: calc(20 * 100vw / 1920);
background: rgba(0, 0, 0, 0.9);
border: 2px solid #f56c6c;
border-radius: 20px;
padding: 40px;
text-align: center;
box-shadow: 0 calc(10 * 100vw / 1920) calc(30 * 100vw / 1920) rgba(0, 0, 0, 0.3);
color: white;
animation: shake 0.5s ease-in-out;
position: relative;
z-index: 10000;
}
.error-icon {
font-size: calc(80 * 100vw / 1920);
margin-bottom: calc(20 * 100vw / 1920);
font-size: 80px;
margin-bottom: 20px;
animation: shake 0.5s ease-in-out;
}
.error-text {
font-size: calc(32 * 100vw / 1920);
font-size: 32px;
font-weight: bold;
color: #f56c6c;
margin-bottom: calc(20 * 100vw / 1920);
margin-bottom: 20px;
}
.correct-answer-text {
font-size: calc(18 * 100vw / 1920);
color: #606266;
background: #f5f7fa;
padding: calc(15 * 100vw / 1920);
border-radius: calc(8 * 100vw / 1920);
border-left: calc(4 * 100vw / 1920) solid #409EFF;
font-size: 18px;
color: white;
background: rgba(64, 158, 255, 0.2);
padding: 15px;
border-radius: 8px;
border-left: 4px solid #409EFF;
}
/* 彩带动画 */
......@@ -297,8 +393,8 @@
.confetti {
position: absolute;
width: calc(10 * 100vw / 1920);
height: calc(10 * 100vw / 1920);
width: 10px;
height: 10px;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57);
animation: confettiFall 3s linear infinite;
}
......@@ -365,69 +461,75 @@
}
}
/* 响应式断点 - 保持布局不变,只调整基准值 */
@media (max-width: 1200px) {
/* 中等屏幕:使用较小的基准值 */
.option-item {
flex: 0 0 calc(280 * 100vw / 1920);
max-width: calc(280 * 100vw / 1920);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
/* 小屏幕:调整基准值但保持比例 */
.question-container {
padding: calc(20 * 100vw / 1920);
.question-content {
padding: 20px;
max-width: 90vw;
}
.options-section {
flex-direction: column;
align-items: center;
.question-text {
font-size: 16px;
}
.question-text h3 {
font-size: 16px;
}
.options-grid.text-only {
grid-template-columns: 1fr;
gap: 15px;
}
.option-item {
flex: 0 0 auto;
max-width: 100%;
width: 100%;
min-height: auto;
min-width: 150px;
padding: 15px;
}
.option-content {
flex-direction: row;
align-items: center;
text-align: left;
gap: 10px;
}
.option-image img {
max-width: 60px;
max-height: 60px;
}
.submit-section {
bottom: 10px;
right: 10px;
}
.option-image {
margin-bottom: 0;
margin-right: calc(15 * 100vw / 1920);
.submit-section .el-button {
padding: 10px 20px;
font-size: 14px;
}
}
@media (max-width: 480px) {
.question-section,
.options-section {
padding: 10px;
}
.option-audio {
flex-direction: row;
margin-bottom: 0;
margin-right: calc(15 * 100vw / 1920);
.question-content {
padding: 15px;
}
.option-text {
flex-direction: row;
align-items: center;
flex: 1;
.options-grid {
gap: 10px;
}
.option-label {
margin-bottom: 0;
margin-right: calc(8 * 100vw / 1920);
.option-item {
padding: 12px;
min-width: 120px;
}
.option-status {
margin-top: 0;
margin-left: calc(15 * 100vw / 1920);
.option-text-content {
font-size: 12px;
}
.submit-section .el-button {
display: block;
width: 100%;
margin: calc(10 * 100vw / 1920) 0;
.option-label {
font-size: 14px;
}
}
\ No newline at end of file
......@@ -19,49 +19,44 @@
<div class="question-container" v-if="questionData">
<!-- 题干部分 -->
<div class="question-section">
<div class="question-text" v-if="questionData.question">
<h3>{{ questionData.question }}</h3>
</div>
<div class="question-content">
<div class="question-image" v-if="questionData.image_url">
<img :src="questionData.image_url" alt="题干图片">
</div>
<div class="question-image" v-if="questionData.image_url">
<img :src="questionData.image_url" alt="题干图片">
</div>
<div class="question-audio" v-if="questionData.audio_url">
<el-button size="small" type="primary" @click="toggleQuestionAudio">
<i :class="questionData.isPlaying ? 'el-icon-video-pause' : 'el-icon-video-play'"></i>
{{ questionData.isPlaying ? '暂停' : '播放' }}题目音频
</el-button>
<audio ref="questionAudio" :src="questionData.audio_url" @ended="questionAudioEnded" style="display: none;"></audio>
<div class="question-text" v-if="questionData.question">
<div class="audio-icon" v-if="questionData.audio_url" @click="toggleQuestionAudio">
<i :class="questionData.isPlaying ? 'el-icon-video-pause' : 'el-icon-video-play'"></i>
</div>
<audio ref="questionAudio" :src="questionData.audio_url" @ended="questionAudioEnded" style="display: none;"></audio>
<h3>{{ questionData.question }}</h3>
</div>
</div>
</div>
<!-- 选项部分 -->
<div class="options-section">
<div class="option-item"
v-for="(option, index) in questionData.options"
:key="index"
@click="toggleOption(index)"
:class="{ 'selected': selectedOptions.includes(index) }">
<div class="option-content">
<div class="option-text" v-if="option.text">
<span class="option-text-content">{{ option.text }}</span>
</div>
<div class="option-image" v-if="option.image_url">
<img :src="option.image_url" alt="选项图片">
</div>
<div class="option-audio" v-if="option.audio_url">
<el-button size="mini" type="primary" @click.stop="toggleOptionAudio(index)">
<i :class="option.isPlaying ? 'el-icon-video-pause' : 'el-icon-video-play'"></i>
{{ option.isPlaying ? '暂停' : '播放' }}
</el-button>
<audio :ref="'optionAudio' + index" :src="option.audio_url" @ended="optionAudioEnded(index)" style="display: none;"></audio>
</div>
<div class="options-grid" :class="{ 'has-images': hasOptionImages, 'text-only': !hasOptionImages }">
<div class="option-item"
v-for="(option, index) in questionData.options"
:key="index"
@click="toggleOption(index)"
:class="{ 'selected': selectedOptions.includes(index) }">
<div class="option-content">
<div class="option-text">
<div class="option-label">{{ String.fromCharCode(65 + index) }}</div>
<div class="option-text-content" v-if="option.text">
<div class="audio-icon" v-if="option.audio_url" @click.stop="toggleOptionAudio(index)">
<i :class="option.isPlaying ? 'el-icon-video-pause' : 'el-icon-video-play'"></i>
</div>
<audio :ref="'optionAudio' + index" :src="option.audio_url" @ended="optionAudioEnded(index)" style="display: none;"></audio>
<span>{{ option.text }}</span>
</div>
</div>
<div class="option-text">
<span class="option-label">{{ String.fromCharCode(65 + index) }}</span>
<div class="option-image" v-if="option.image_url">
<img :src="option.image_url" alt="选项图片">
</div>
</div>
</div>
</div>
......
......@@ -28,6 +28,15 @@ new Vue({
showError: false
}
},
computed: {
// 判断是否有选项包含图片
hasOptionImages() {
if (!this.questionData || !this.questionData.options) {
return false;
}
return this.questionData.options.some(option => option.image_url && option.image_url.trim() !== '');
}
},
created() {
window.courseware.getData((data) => {
if (data) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment