feat:答题卡页面封装,练习功能全部完成

This commit is contained in:
小张 2025-09-19 01:49:27 +08:00
parent 935c68ac6d
commit 23f6924711
2 changed files with 735 additions and 209 deletions

View File

@ -0,0 +1,169 @@
<template>
<div class="semi-circle-progress">
<div class="progress-container">
<!-- 半圆环SVG -->
<svg :width="size" :height="size / 2 + 20" viewBox="0 0 200 120" class="progress-svg">
<!-- 外层圆弧背景 - 更宽 (#e1edf2) -->
<path
:d="getArcPath(85, 0, 180)"
:stroke="backgroundColors.outer"
:stroke-width="strokeWidth + 8"
fill="none"
stroke-linecap="butt"
/>
<!-- 内层圆弧 - 未得分区域 (#cce2ed) -->
<path
:d="getArcPath(85, 0, 180)"
:stroke="backgroundColors.middle"
:stroke-width="strokeWidth - 4"
fill="none"
stroke-linecap="butt"
/>
<!-- 内层圆弧 - 得分区域 (#0288d1) -->
<path
:d="getArcPath(85, 0, progressAngle)"
:stroke="progressColor"
:stroke-width="strokeWidth - 4"
fill="none"
stroke-linecap="butt"
class="progress-path"
/>
</svg>
<!-- 中心内容 -->
<div class="progress-content">
<div class="progress-label">{{ label }}</div>
<div class="progress-value">{{ displayValue }}</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
interface Props {
value: number //
maxValue?: number // 100
size?: number // 200
strokeWidth?: number // 线16
label?: string // ""
progressColor?: string // #0288d1
backgroundColors?: {
outer: string // #e1edf2
middle: string // #cce2ed
}
showPercentage?: boolean // false
}
const props = withDefaults(defineProps<Props>(), {
maxValue: 100,
size: 200,
strokeWidth: 16,
label: '得分',
progressColor: '#0288d1',
backgroundColors: () => ({
outer: '#e1edf2',
middle: '#cce2ed'
}),
showPercentage: false
})
// (0-180)
const progressAngle = computed(() => {
const percentage = Math.min(props.value / props.maxValue, 1)
return percentage * 180
})
//
const displayValue = computed(() => {
if (props.showPercentage) {
const percentage = Math.round((props.value / props.maxValue) * 100)
return `${percentage}%`
}
return props.value.toString()
})
// ()
const getArcPath = (radius: number, startAngle: number, endAngle: number) => {
const centerX = 100
const centerY = 100
// 0180
// 使
const startAngleRad = ((180 - startAngle) * Math.PI) / 180
const endAngleRad = ((180 - endAngle) * Math.PI) / 180
const startX = centerX + radius * Math.cos(startAngleRad)
const startY = centerY - radius * Math.sin(startAngleRad)
const endX = centerX + radius * Math.cos(endAngleRad)
const endY = centerY - radius * Math.sin(endAngleRad)
const largeArcFlag = endAngle - startAngle > 90 ? 1 : 0
return `M ${startX} ${startY} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${endX} ${endY}`
}
</script>
<style scoped>
.semi-circle-progress {
display: flex;
justify-content: center;
align-items: center;
}
.progress-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.progress-svg {
display: block;
}
.progress-path {
transition: stroke-dashoffset 0.8s ease-in-out;
}
.progress-content {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
text-align: center;
z-index: 10;
}
.progress-label {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #999999;
line-height: 17px;
margin-bottom: 4px;
}
.progress-value {
font-family: PingFangSC, PingFang SC;
font-weight: bold;
font-size: 36px;
color: #333333;
line-height: 1;
}
/* 响应式调整 */
@media (max-width: 768px) {
.progress-value {
font-size: 28px;
}
.progress-label {
font-size: 10px;
}
}
</style>

View File

@ -44,7 +44,7 @@
</div>
</div>
<!-- 提示 - 练习模式和讨论模式下隐藏 -->
<!-- 提示 - 练习模式和讨论模式下显示不同内容 -->
<div v-if="!practiceMode && !discussionMode" class="tip-section">
<img src="/images/aiCompanion/ii.jpg" alt="">
<span>此视频请在2025.10.23 23:59前完成学习快进拖拽或逾期学习不计入观看进度和成绩</span>
@ -55,178 +55,213 @@
</div>
</div>
<!-- 练习模式界面 -->
<div v-if="practiceMode" class="practice-section">
<!-- 练习说明页面 -->
<div v-if="!practiceStarted" class="practice-instructions">
<div class="instructions-card">
<h3>练习说明</h3>
<ul>
<li>本次练习共{{ practiceQuestions.length }}道题总分{{ practiceQuestions.reduce((sum, q) => sum + q.score, 0) }}</li>
<li>练习没有时间限制可以随时暂停和继续</li>
<li>每道题可以多次修改答案</li>
<li>完成后可以查看正确答案和解析</li>
<li>练习结果不会影响最终成绩</li>
</ul>
<div class="practice-actions">
<button class="btn-start-practice" @click="startPractice">开始练习</button>
<button class="btn-back-practice" @click="exitPractice">返回课程</button>
<!-- 练习/讨论模式界面 -->
<div v-if="practiceMode || discussionMode" class="practice-section">
<!-- 整体横向布局 -->
<div class="practice-overall-layout">
<!-- 左侧纵向盒子 -->
<div class="practice-left-container">
<!-- 面包屑导航 -->
<div class="breadcrumb-section">
<div class="breadcrumb">
<span class="breadcrumb-course">{{ course.name }}</span>
<span class="breadcrumb-separator"> > </span>
<span class="breadcrumb-current">{{ practiceMode ? currentPracticeSection?.name || '练习' : '讨论' }}</span>
</div>
</div>
<!-- 提示区域 -->
<div class="tip-section practice-tip">
<img src="/images/aiCompanion/ii.jpg" alt="">
<span>{{ practiceMode ? '此练习' : '此讨论' }}请在2025.10.23 23:59前完成学习快进拖拽或逾期学习不计入观看进度和成绩</span>
<div class="tip-section-box">
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 1L9 9M9 1L1 9" stroke="#999999" stroke-width="1.5" stroke-linecap="round" />
</svg>
</div>
</div>
<!-- 练习答题区域 -->
<div v-if="practiceStarted && !practiceFinished" class="practice-content">
<div class="question-card" v-if="currentPracticeQuestion">
<div class="question-header">
<span class="question-title-info">{{ String(currentQuestionIndex + 1).padStart(2, '0') }}{{ getPracticeQuestionTypeShort(currentPracticeQuestion.type) }}<span>{{ currentPracticeQuestion.score }}</span></span>
</div>
<div class="question-content">
<div class="question-title">
{{ currentPracticeQuestion.title }}
</div>
<!-- 选择题选项 -->
<div v-if="currentPracticeQuestion.type === '单选题' || currentPracticeQuestion.type === '多选题' || currentPracticeQuestion.type === '判断题'" class="question-options">
<div v-for="(option, index) in currentPracticeQuestion.options" :key="index"
class="option-item"
:class="{ 'selected': isPracticeOptionSelected(index) }"
@click="selectPracticeOption(index)">
<div class="option-checkbox">
<input type="checkbox"
:name="`practice-question-${currentQuestionIndex}`"
:checked="isPracticeOptionSelected(index)"
@change="handlePracticeCheckboxClick(index, $event)"
@click="handlePracticeCheckboxClick(index, $event)">
</div>
<span class="option-label">{{ String.fromCharCode(65 + index) }}.</span>
<span class="option-text">{{ option }}</span>
</div>
</div>
<!-- 填空题输入框 -->
<div v-else-if="currentPracticeQuestion.type === '填空题'" class="fill-blank">
<div class="fill-item" v-for="(_, index) in currentPracticeQuestion.blanks || [1]" :key="index">
<span class="fill-number">{{ index + 1 }}.</span>
<input type="text"
:value="getPracticeFillAnswer(currentQuestionIndex, index)"
@input="setPracticeFillAnswer(currentQuestionIndex, index, $event.target.value)"
placeholder=""
class="fill-input" />
</div>
<div class="fill-hint">
*请在上方输入框内输入填空内容
</div>
</div>
<!-- 简答题文本域 -->
<div v-else-if="currentPracticeQuestion.type === '简答题'" class="essay-answer">
<div class="essay-container">
<textarea v-model="essayAnswers[currentQuestionIndex]"
placeholder=""
class="essay-textarea"
rows="8"
maxlength="500"></textarea>
</div>
<div class="essay-footer">
<div class="essay-hint">
*请在上方输入框内输入答案内容
</div>
<div class="essay-counter">
{{ getPracticeEssayLength(currentQuestionIndex) }}/500
</div>
</div>
</div>
</div>
<div class="question-navigation">
<button class="btn-nav btn-prev" @click="previousPracticeQuestion" :disabled="currentQuestionIndex === 0">
上一题
</button>
<button class="btn-nav btn-next" @click="nextPracticeQuestion">
下一题
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 练习主体内容 -->
<div v-if="practiceStarted && !practiceFinished" class="practice-main">
<div class="practice-layout">
<!-- 中间答题区域 -->
<div class="practice-content">
<div class="question-card" v-if="currentPracticeQuestion">
<div class="question-header">
<span class="question-title-info">{{ String(currentQuestionIndex + 1).padStart(2, '0') }}{{ getPracticeQuestionTypeShort(currentPracticeQuestion.type) }}<span>{{ currentPracticeQuestion.score }}</span></span>
<!-- 右侧答题卡 -->
<div v-if="practiceStarted && !practiceFinished" class="practice-answer-card">
<div class="answer-card-container">
<!-- 答题报告标题 -->
<div class="answer-card-header">
<div class="answer-card-title">答题报告</div>
</div>
<div class="question-content">
<div class="question-title">
{{ currentPracticeQuestion.title }}
</div>
<!-- 分割线 -->
<div class="divider-line"></div>
<!-- 选择题选项 -->
<div v-if="currentPracticeQuestion.type === '单选题' || currentPracticeQuestion.type === '多选题' || currentPracticeQuestion.type === '判断题'" class="question-options">
<div v-for="(option, index) in currentPracticeQuestion.options" :key="index"
class="option-item"
:class="{ 'selected': isPracticeOptionSelected(index) }"
@click="selectPracticeOption(index)">
<div class="option-checkbox">
<input type="checkbox"
:name="`practice-question-${currentQuestionIndex}`"
:checked="isPracticeOptionSelected(index)"
@change="handlePracticeCheckboxClick(index, $event)"
@click="handlePracticeCheckboxClick(index, $event)">
</div>
<span class="option-label">{{ String.fromCharCode(65 + index) }}.</span>
<span class="option-text">{{ option }}</span>
</div>
</div>
<!-- 当前得分圆环 -->
<div class="score-circle-container">
<SemiCircleProgress
:value="getCurrentPracticeScore()"
:max-value="getTotalPracticeScore()"
label="当前得分"
:size="190"
:stroke-width="16"
progress-color="#0288d1"
:background-colors="{
outer: '#e1edf2',
middle: '#cce2ed'
}"
/>
<!-- 难度标签移到圆环右上角 -->
<div class="difficulty-tag-circle">难度·4.8</div>
</div>
<!-- 填空题输入框 -->
<div v-else-if="currentPracticeQuestion.type === '填空题'" class="fill-blank">
<div class="fill-item" v-for="(_, index) in currentPracticeQuestion.blanks || [1]" :key="index">
<span class="fill-number">{{ index + 1 }}.</span>
<input type="text"
:value="getPracticeFillAnswer(currentQuestionIndex, index)"
@input="setPracticeFillAnswer(currentQuestionIndex, index, $event.target.value)"
placeholder=""
class="fill-input" />
</div>
<div class="fill-hint">
*请在上方输入框内输入填空内容
</div>
<!-- 答题信息 -->
<div class="answer-info">
<div class="info-item">
<span class="info-label">答题时间</span>
<span class="info-value">2025.07.13 12:34</span>
</div>
<!-- 简答题文本域 -->
<div v-else-if="currentPracticeQuestion.type === '简答题'" class="essay-answer">
<div class="essay-container">
<textarea v-model="essayAnswers[currentQuestionIndex]"
placeholder=""
class="essay-textarea"
rows="8"
maxlength="500"></textarea>
</div>
<div class="essay-footer">
<div class="essay-hint">
*请在上方输入框内输入答案内容
</div>
<div class="essay-counter">
{{ getPracticeEssayLength(currentQuestionIndex) }}/500
</div>
</div>
<div class="info-item">
<span class="info-label">答题时长</span>
<span class="info-value">1分23秒</span>
</div>
<div class="info-item">
<span class="info-label">答题总数</span>
<span class="info-value">{{ getAnsweredCount() }}/{{ practiceQuestions.length }}</span>
</div>
</div>
<div class="question-navigation">
<button class="btn-nav btn-prev" @click="previousPracticeQuestion" :disabled="currentQuestionIndex === 0">
上一题
</button>
<button class="btn-nav btn-next" @click="nextPracticeQuestion">
下一题
</button>
</div>
</div>
</div>
<!-- 分割线 -->
<div class="divider-line"></div>
<!-- 右侧答题卡 -->
<div class="practice-answer-card">
<div class="answer-card-container">
<!-- 答题报告标题 -->
<div class="answer-card-header">
<h3>答题报告</h3>
<div class="difficulty-tag">难度·4.8</div>
</div>
<!-- 当前得分圆环 -->
<div class="score-circle-container">
<div class="score-circle">
<svg width="120" height="120" viewBox="0 0 120 120">
<circle cx="60" cy="60" r="50" fill="none" stroke="#f0f0f0" stroke-width="8"/>
<circle cx="60" cy="60" r="50" fill="none" stroke="#1890ff" stroke-width="8"
:stroke-dasharray="314"
:stroke-dashoffset="314 - (314 * getPracticeProgress() / 100)"
transform="rotate(-90 60 60)"/>
</svg>
<div class="score-text">
<div class="current-score">{{ getCurrentPracticeScore() }}</div>
<div class="score-label">当前得分</div>
</div>
</div>
</div>
<!-- 答题信息 -->
<div class="answer-info">
<div class="info-item">
<span class="info-label">答题时间</span>
<span class="info-value">--</span>
</div>
<div class="info-item">
<span class="info-label">答题时长</span>
<span class="info-value">--</span>
</div>
<div class="info-item">
<span class="info-label">答题总数</span>
<span class="info-value">{{ getAnsweredCount() }}/{{ practiceQuestions.length }}</span>
</div>
</div>
<!-- 得分情况 -->
<div class="score-breakdown">
<h4>得分情况</h4>
<div class="score-item">
<!-- 得分情况 -->
<div class="score-breakdown">
<div class="score-breakdown-title">得分情况</div>
<div class="score-item">
<div class="score-item-content">
<span class="score-type">单选</span>
<div class="score-progress-bar">
<div class="score-progress-fill" :style="{ width: getSingleChoiceProgress() + '%' }"></div>
</div>
<span class="score-count">{{ getSingleChoiceScore() }}/{{ getSingleChoiceTotal() }}</span>
</div>
<div class="score-item">
</div>
<div class="score-item">
<div class="score-item-content">
<span class="score-type">多选</span>
<div class="score-progress-bar">
<div class="score-progress-fill" :style="{ width: getMultiChoiceProgress() + '%' }"></div>
</div>
<span class="score-count">{{ getMultiChoiceScore() }}/{{ getMultiChoiceTotal() }}</span>
</div>
<div class="score-item">
</div>
<div class="score-item">
<div class="score-item-content">
<span class="score-type">判断</span>
<div class="score-progress-bar">
<div class="score-progress-fill" :style="{ width: getJudgeProgress() + '%' }"></div>
</div>
<span class="score-count">{{ getJudgeScore() }}/{{ getJudgeTotal() }}</span>
</div>
</div>
</div>
<!-- 排名信息 -->
<div class="ranking-info">
<div class="ranking-item">
<div class="ranking-number">6</div>
<div class="ranking-label">最高分</div>
</div>
<div class="ranking-item">
<div class="ranking-number">30</div>
<div class="ranking-label">练习人数3892人</div>
</div>
<div class="ranking-item">
<div class="ranking-number">90</div>
<div class="ranking-label">答错人数</div>
<!-- 分割线 -->
<div class="divider-line"></div>
<!-- 排名信息 -->
<div class="ranking-info">
<div class="ranking-item ranking-item-left">
<div class="ranking-number">6</div>
<div class="ranking-label">最高分</div>
</div>
<div class="ranking-divider"></div>
<div class="ranking-item ranking-item-center">
<div class="ranking-number-with-text">
<span class="ranking-prefix"></span>
<span class="ranking-number">30</span>
<span class="ranking-suffix"></span>
</div>
<div class="ranking-label">练习人数3892人</div>
</div>
<div class="ranking-divider"></div>
<div class="ranking-item ranking-item-right">
<div class="ranking-number">90</div>
<div class="ranking-label">答错人数</div>
</div>
</div>
</div>
@ -1332,6 +1367,7 @@ import type { Course, CourseSection, CourseComment } from '@/api/types'
import QuillEditor from '@/components/common/QuillEditor.vue'
import DPlayerVideo from '@/components/course/DPlayerVideo.vue'
import SafeAvatar from '@/components/common/SafeAvatar.vue'
import SemiCircleProgress from '@/components/common/SemiCircleProgress.vue'
// import LoginModal from '@/components/auth/LoginModal.vue'
// import RegisterModal from '@/components/auth/RegisterModal.vue'
@ -2383,7 +2419,7 @@ const handlePractice = async (section: CourseSection) => {
practiceQuestions.value = mockQuestions
currentPracticeSection.value = section
practiceMode.value = true
practiceStarted.value = false
practiceStarted.value = true //
practiceFinished.value = false
currentQuestionIndex.value = 0
@ -2568,6 +2604,32 @@ const getJudgeTotal = () => {
return practiceQuestions.value.filter(q => q.type === '判断题').length
}
//
const getSingleChoiceProgress = () => {
const total = getSingleChoiceTotal()
if (total === 0) return 0
return Math.round((getSingleChoiceScore() / total) * 100)
}
const getMultiChoiceProgress = () => {
const total = getMultiChoiceTotal()
if (total === 0) return 0
return Math.round((getMultiChoiceScore() / total) * 100)
}
const getJudgeProgress = () => {
const total = getJudgeTotal()
if (total === 0) return 0
return Math.round((getJudgeScore() / total) * 100)
}
//
const getTotalPracticeScore = () => {
return practiceQuestions.value.reduce((total, question) => {
return total + (question.score || 0)
}, 0)
}
//
const handleExam = (section: CourseSection) => {
console.log('开始考试:', section)
@ -3161,10 +3223,77 @@ onActivated(() => {
padding-right: 120px;
}
.breadcrumb {
/* 练习/讨论模式整体布局 */
.practice-overall-layout {
display: flex;
gap: 20px;
align-items: flex-start;
}
.practice-left-container {
width: 70%;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 0;
}
.practice-answer-card {
width: 300px;
flex-shrink: 0;
align-self: flex-start;
margin-top: 72px; /* 与提示区域顶部对齐 */
}
/* 面包屑导航样式 */
.breadcrumb-section {
padding: 12px 0;
}
.breadcrumb {
display: flex;
align-items: center;
font-size: 14px;
line-height: 20px;
}
.breadcrumb-course {
width: 70px;
height: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #333333;
line-height: 20px;
text-align: left;
font-style: normal;
cursor: pointer;
}
.breadcrumb-separator {
margin: 0 8px;
color: #333333;
}
.breadcrumb-current {
width: 154px;
height: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #999999;
line-height: 20px;
text-align: left;
font-style: normal;
}
/* 练习模式提示样式调整 */
.tip-section.practice-tip {
width: 100%; /* 占满左侧容器宽度 */
background: rgba(255, 255, 255, 0.5);
margin-bottom: 20px;
}
.breadcrumb-text {
color: #666;
font-size: 14px;
@ -7511,9 +7640,9 @@ onActivated(() => {
/* 练习模式样式 */
.practice-section {
background: white;
border-radius: 8px;
overflow: hidden;
background: transparent; /* 改为透明 */
border-radius: 0;
overflow: visible;
width: 100%;
max-width: none;
}
@ -7599,29 +7728,13 @@ onActivated(() => {
background: #e6f7ff;
}
.practice-main {
padding: 20px;
}
.practice-layout {
display: flex;
gap: 24px;
width: 100%;
align-items: flex-start;
}
.practice-sidebar {
width: 300px;
flex-shrink: 0;
}
.practice-content {
flex: 1;
min-width: 0;
background: white;
border-radius: 8px;
width: 100%;
background: rgba(255, 255, 255, 0.5);
border-radius: 2px;
border: 1px solid #FFFFFF;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
min-height: 560px;
}
.answer-sheet {
@ -7743,72 +7856,87 @@ onActivated(() => {
}
.question-card {
background: white;
border: 1px solid #e8e8e8;
border-radius: 8px;
padding: 30px;
height: 100%;
display: flex;
flex-direction: column;
background: transparent;
border: none;
border-radius: 0;
padding: 0;
}
.question-header {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #f0f0f0;
margin-bottom: 12px;
}
.question-title-info {
color: #0088D1;
font-size: 16px;
color: #1890ff;
font-weight: 500;
}
.question-title-info span {
color: #ff4d4f;
background-color: #EEF9FF;
font-size: 12px;
padding: 2px 4px;
border-radius: 10px;
}
.question-content {
margin-bottom: 30px;
flex: 1;
margin-bottom: 24px;
}
.question-title {
font-size: 18px;
font-size: 16px;
font-weight: 400;
color: #333;
line-height: 1.6;
margin-bottom: 20px;
margin: 0 0 24px 0;
line-height: 1.8;
}
.question-options {
margin-top: 20px;
margin-bottom: 24px;
}
.option-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 12px;
border: 1px solid #e8e8e8;
align-items: center;
padding: 5px 20px;
border: none;
border-radius: 6px;
margin-bottom: 12px;
margin-bottom: 16px;
cursor: pointer;
transition: all 0.3s;
background: #EEF9FF;
min-height: 50px;
}
.option-item:hover {
border-color: #1890ff;
background: #f6ffed;
background: #EEF9FF;
}
.option-item.selected {
border-color: #1890ff;
background: #e6f7ff;
background: #EEF9FF;
color: #333;
}
.option-checkbox input {
.option-checkbox {
margin-right: 12px;
position: relative;
}
.option-checkbox input[type="checkbox"] {
width: 16px;
height: 16px;
margin: 0;
cursor: pointer;
}
.option-label {
font-weight: 500;
color: #333;
margin-right: 8px;
min-width: 20px;
}
@ -7954,25 +8082,77 @@ onActivated(() => {
}
}
/* 练习答题卡样式 */
.practice-answer-card {
/* 答题卡容器样式 */
.answer-card-container {
width: 300px;
flex-shrink: 0;
height: 566px;
background: rgba(255, 255, 255, 0.5);
border: 1px solid #FFFFFF;
border-radius: 0;
box-shadow: none;
padding: 20px;
}
.answer-card-container {
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
padding: 20px;
border: 1px solid #e8e8e8;
/* 答题报告标题 */
.answer-card-title {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 16px;
color: #000000;
line-height: 22px;
text-align: center;
margin-bottom: 16px;
width: 100%;
display: flex;
justify-content: center;
}
/* 圆环右上角的难度标签 */
.difficulty-tag-circle {
position: absolute;
top: 0px;
right: 5px;
width: 56px;
height: 20px;
background: #0288D1;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-family: AppleSystemUIFont;
font-size: 10px;
color: #FFFFFF;
line-height: 14px;
text-align: left;
font-style: normal;
text-transform: none;
white-space: nowrap;
z-index: 10;
}
/* 分割线 */
.divider-line {
width: 252px;
height: 1px;
border: 1px solid #E6E6E6;
margin: 16px auto;
}
/* 得分圆环容器 */
.score-circle-container {
display: flex;
justify-content: center;
margin: 20px 0;
position: relative; /* 为难度标签提供定位基准 */
}
/* 使用新的SemiCircleProgress组件移除旧的圆环样式 */
.answer-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
margin-bottom: -20px;
}
.answer-card-header h3 {
@ -8346,4 +8526,181 @@ onActivated(() => {
background: #52c41a;
color: white;
}
/* 新的答题卡样式 */
/* 答题信息样式 */
.answer-info {
margin: 20px 0;
}
.info-item {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 8px;
padding-left: 20px;
gap: 2px; /* 非常小的间距 */
}
.info-label {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #999999;
line-height: 17px;
text-align: left;
font-style: normal;
flex-shrink: 0;
}
.info-value {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #999999;
line-height: 17px;
flex-shrink: 0;
}
/* 得分情况样式 */
.score-breakdown {
margin: 20px 0;
}
.score-breakdown-title {
width: 100%;
height: 22px;
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 16px;
color: #000000;
line-height: 22px;
text-align: center;
font-style: normal;
margin-bottom: 16px;
display: flex;
justify-content: center;
}
.score-item {
margin-bottom: 12px; /* 减少高度 */
}
.score-item-content {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #999999;
line-height: 17px;
}
.score-type {
width: 30px;
flex-shrink: 0;
}
.score-progress-bar {
width: 150px; /* 增加宽度,让进度条更长 */
height: 8px;
background: #E6E6E6;
border-radius: 5px;
overflow: hidden;
flex-shrink: 0;
}
.score-progress-fill {
height: 100%;
background: #0288D1;
border-radius: 5px;
transition: width 0.3s ease;
}
.score-count {
margin-left: 8px;
flex-shrink: 0;
}
/* 排名信息样式 */
.ranking-info {
display: flex;
align-items: center;
justify-content: space-between;
margin: 20px 0;
padding: 0 10px;
}
.ranking-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.ranking-item-left {
margin-left: -20px; /* 左边项目往左移 */
}
.ranking-item-right {
margin-right: -20px; /* 右边项目往右移 */
}
.ranking-number {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 24px;
color: #F38505;
line-height: 33px;
text-align: center;
font-style: normal;
text-transform: none;
}
.ranking-number-with-text {
display: flex;
align-items: center;
justify-content: center;
height: 33px;
}
.ranking-prefix {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 10px;
color: #999999;
line-height: 14px;
text-align: left;
font-style: normal;
margin-right: 4px; /* 往左,增加与数字的间距 */
}
.ranking-suffix {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 10px;
color: #999999;
line-height: 14px;
text-align: left;
font-style: normal;
margin-left: 4px; /* 往右,增加与数字的间距 */
}
.ranking-label {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #999999;
line-height: 17px;
text-align: center;
margin-top: 4px;
white-space: nowrap; /* 防止换行,保持一行显示 */
}
.ranking-divider {
width: 1px;
height: 40px;
background: #EDEDED;
}
</style>