2026-05-26 17:12:12 +08:00

1038 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="rep-page">
<!-- 装饰背景 -->
<view class="bg-decor bg-decor-a"></view>
<view class="bg-decor bg-decor-b"></view>
<view class="bg-decor bg-decor-c"></view>
<!-- Tabs -->
<view class="tab-bar">
<view class="tab-segment">
<view
v-for="t in tabs"
:key="t.id"
:class="['tab-item', { active: activeType === t.id }]"
@click="activeType = t.id"
>
<text>{{ t.name }}</text>
</view>
</view>
</view>
<scroll-view v-if="!pageLoading" class="rep-scroll" scroll-y :show-scrollbar="false">
<!-- 整体分析 -->
<view v-if="activeType === '0'" class="tab-content">
<!-- Score Hero Card -->
<view class="score-hero" :style="{ background: heroGradient }">
<view class="score-hero-deco"></view>
<view class="score-hero-content">
<view class="score-hero-circle">
<view class="score-ring" :style="ringStyle">
<view class="score-ring-inner">
<view class="score-ring-num">
<text class="num">{{ correctRate }}</text>
<text class="unit">%</text>
</view>
<text class="score-ring-label">正确率</text>
</view>
</view>
</view>
<view class="score-hero-info">
<view class="paper-name">{{ jobAnalyse?.jobReportVo?.jobName || paperName }}</view>
<view class="hero-row">
<view class="hero-stat">
<view class="stat-num">
{{ Number(jobAnalyse?.jobReportVo?.markScore) || 0 }}
<text class="stat-num-unit">/{{ jobAnalyse?.jobReportVo?.totalScore || 100 }}</text>
</view>
<view class="stat-label">得分</view>
</view>
<view class="hero-stat">
<view class="stat-num">{{ costTimeText }}</view>
<view class="stat-label">用时</view>
</view>
</view>
</view>
</view>
</view>
<!-- 答题统计 -->
<view class="card">
<view class="card-title">
<view class="title-bar"></view>
<text>答题统计</text>
</view>
<view class="stat-grid">
<view class="stat-card correct">
<view class="stat-emoji">✓</view>
<view class="stat-value">{{ correctNum }}</view>
<view class="stat-tag">答对</view>
</view>
<view class="stat-card wrong">
<view class="stat-emoji">✕</view>
<view class="stat-value">{{ wrongNum }}</view>
<view class="stat-tag">答错</view>
</view>
<view class="stat-card unanswered">
<view class="stat-emoji"></view>
<view class="stat-value">{{ unansweredNum }}</view>
<view class="stat-tag">未答</view>
</view>
</view>
</view>
<!-- 题型分布 -->
<view v-if="channelAnalyzeList.length" class="card">
<view class="card-title">
<view class="title-bar"></view>
<text>题型分布</text>
</view>
<view class="pie-row">
<view class="pie">
<view class="pie-circle" :style="pieChartStyle"></view>
<view class="pie-hole">
<text class="pie-hole-num">{{ totalQuestions }}</text>
<text class="pie-hole-label"></text>
</view>
</view>
<view class="pie-legend">
<view
v-for="(item, idx) in channelAnalyzeList"
:key="idx"
class="legend-item"
>
<view
class="legend-dot"
:style="{ background: pieColors[idx % pieColors.length] }"
></view>
<text class="legend-name">{{ item.chanelTypeName }}</text>
<text class="legend-count">{{ item.titleCount }}</text>
</view>
</view>
</view>
</view>
<!-- 难度分布 -->
<view v-if="difficultyAnalyzeList.length" class="card">
<view class="card-title">
<view class="title-bar"></view>
<text>难度分布</text>
</view>
<view class="bars">
<view
v-for="(item, idx) in difficultyAnalyzeList"
:key="idx"
class="bar-row"
>
<view class="bar-name">{{ item.difficultyName }}</view>
<view class="bar-track">
<view
class="bar-fill"
:style="{
width: getBarWidth(item.score) + '%',
background: difficultyColors[item.difficultyName] || '#818CF8',
}"
></view>
</view>
<view class="bar-value">{{ item.score }}<text class="bar-value-unit"></text></view>
</view>
</view>
</view>
</view>
<!-- 答题详情 -->
<view v-else-if="activeType === '1'" class="tab-content">
<view class="card">
<view class="card-title">
<view class="title-bar"></view>
<text>答题情况 · {{ paperList.length }}</text>
</view>
<view v-if="paperList.length" class="qnum-grid">
<view
v-for="(item, idx) in paperList"
:key="item.id"
:class="['qnum-card', getStatusClass(item)]"
@click="viewQuestion(idx)"
>
<text class="qnum-card-num">{{ idx + 1 }}</text>
<view class="qnum-card-status">
<text>{{ getStatusText(item) }}</text>
</view>
</view>
</view>
<Empty v-else type="task" content="暂无题目数据" />
</view>
<view class="legend-card">
<view class="legend-card-item">
<view class="legend-mark correct"></view>
<text>正确</text>
</view>
<view class="legend-card-item">
<view class="legend-mark wrong"></view>
<text>错误</text>
</view>
<view class="legend-card-item">
<view class="legend-mark unanswered"></view>
<text>未答</text>
</view>
</view>
</view>
<!-- 知识点 -->
<view v-else-if="activeType === '2'" class="tab-content">
<view v-if="knowledgeList.length" class="knowledge-list">
<view
v-for="(item, idx) in knowledgeList"
:key="idx"
class="knowledge-item"
>
<view class="knowledge-head">
<view class="knowledge-name">{{ item.knowledgeName }}</view>
<view
class="knowledge-score"
:style="{ color: getKnowledgeScoreColor(item) }"
>
<text class="kn-num">{{ item.answerScore }}</text>
<text class="kn-divider">/</text>
<text class="kn-total">{{ item.titleScore }}</text>
</view>
</view>
<ProgressBar
:rate="getKnowledgeRate(item)"
:width="660"
v-bind="getKnowledgeColor(item)"
/>
</view>
</view>
<Empty v-else type="task" content="暂无知识点数据" />
</view>
<view style="height: 80rpx"></view>
</scroll-view>
<!-- 加载 -->
<view v-if="pageLoading" class="page-loader">
<Loading text="加载报告中..." />
</view>
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import Empty from '@/components/Empty/index.vue';
import Loading from '@/components/Loading/index.vue';
import ProgressBar from '@/components/ProgressBar/index.vue';
import { getJobAnalyse, getKnowledgeAnalyse, getPaperRecordDetail } from '@/api/homework';
const recordId = ref('');
const paperName = ref('');
const pageLoading = ref(true);
const activeType = ref('0');
const jobAnalyse = ref<any>({});
const paperList = ref<any[]>([]);
const knowledgeList = ref<any[]>([]);
const tabs = [
{ id: '0', name: '整体分析' },
{ id: '1', name: '答题详情' },
{ id: '2', name: '知识点' },
];
const pieColors = ['#4F46E5', '#22C55E', '#F59E0B', '#EF4444', '#0EA5E9', '#A855F7', '#EC4899'];
const difficultyColors: Record<string, string> = {
'容易': '#22C55E',
'较易': '#0EA5E9',
'普通': '#F59E0B',
'较难': '#EF4444',
'困难': '#7C3AED',
};
const channelAnalyzeList = computed(() => jobAnalyse.value?.paperChanelAnalyzeList || []);
const difficultyAnalyzeList = computed(() => jobAnalyse.value?.paperDifficultyAnalyzeList || []);
const totalQuestions = computed(() => {
return channelAnalyzeList.value.reduce(
(sum: number, item: any) => sum + (item.titleCount || 0),
0,
);
});
const pieChartStyle = computed(() => {
const data = channelAnalyzeList.value;
if (!data.length) return {};
const total = data.reduce((sum: number, item: any) => sum + (item.titleCount || 0), 0);
if (total === 0) return {};
const parts: string[] = [];
let cur = 0;
data.forEach((item: any, idx: number) => {
const pct = (item.titleCount / total) * 100;
const color = pieColors[idx % pieColors.length];
const next = cur + pct;
parts.push(`${color} ${cur}% ${next}%`);
cur = next;
});
return { background: `conic-gradient(${parts.join(', ')})` };
});
const correctNum = computed(() => {
return paperList.value.filter(
(item) => item.correctResult === 1 || item.correctResult === true,
).length;
});
const wrongNum = computed(() => {
return paperList.value.filter(
(item) =>
(item.correctResult === 0 || item.correctResult === false) &&
(item.submitAnswer || item.submitAnswerPic),
).length;
});
const unansweredNum = computed(() => {
return paperList.value.filter((item) => !item.submitAnswer && !item.submitAnswerPic).length;
});
const correctRate = computed(() => {
const total = paperList.value.length;
if (total === 0) return 0;
return Math.round((correctNum.value / total) * 100);
});
const scoreColor = computed(() => {
const r = Number(correctRate.value) || 0;
if (r >= 80) return '#22C55E';
if (r >= 60) return '#4F46E5';
if (r >= 40) return '#F59E0B';
return '#EF4444';
});
const heroGradient = computed(() => {
const r = Number(correctRate.value) || 0;
if (r >= 80) return 'linear-gradient(135deg, #DCFCE7 0%, #BBF7D0 100%)';
if (r >= 60) return 'linear-gradient(135deg, #E0E7FF 0%, #C7D2FE 100%)';
if (r >= 40) return 'linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%)';
return 'linear-gradient(135deg, #FEE2E2 0%, #FECACA 100%)';
});
const ringStyle = computed(() => ({
background: `conic-gradient(${scoreColor.value} 0% ${correctRate.value}%, rgba(255,255,255,0.6) ${correctRate.value}% 100%)`,
}));
const costTimeText = computed(() => {
const ms = Number(jobAnalyse.value?.jobReportVo?.costTime || 0);
const total = Math.floor(ms / 1000);
const h = Math.floor(total / 3600);
const m = Math.floor((total % 3600) / 60);
const s = total % 60;
if (h > 0) return `${h}${m}${s}`;
if (m > 0) return `${m}${s}`;
return `${s}`;
});
const getBarWidth = (score: number) => {
const max = Math.max(...difficultyAnalyzeList.value.map((i: any) => i.score || 0), 1);
return Math.round((score / max) * 100);
};
const getStatusClass = (item: any) => {
if (item.correctResult === 1 || item.correctResult === true) return 'correct';
if (!item.submitAnswer && !item.submitAnswerPic) return 'unanswered';
return 'wrong';
};
const getStatusText = (item: any) => {
if (item.correctResult === 1 || item.correctResult === true) return '正确';
if (!item.submitAnswer && !item.submitAnswerPic) return '未答';
return '错误';
};
const getKnowledgeRate = (item: any) => {
const t = Number(item.titleScore) || 1;
const s = Number(item.answerScore) || 0;
return s / t;
};
const getKnowledgeScoreColor = (item: any) => {
const r = getKnowledgeRate(item) * 100;
if (r >= 80) return '#16A34A';
if (r >= 60) return '#4F46E5';
if (r >= 40) return '#D97706';
return '#DC2626';
};
const getKnowledgeColor = (item: any) => {
const r = getKnowledgeRate(item) * 100;
if (r >= 80) return { bg: '#DCFCE7', border: '#BBF7D0', activeBg: 'linear-gradient(90deg, #4ADE80, #16A34A)' };
if (r >= 60) return { bg: '#E0E7FF', border: '#C7D2FE', activeBg: 'linear-gradient(90deg, #818CF8, #4F46E5)' };
if (r >= 40) return { bg: '#FEF3C7', border: '#FDE68A', activeBg: 'linear-gradient(90deg, #FBBF24, #D97706)' };
return { bg: '#FEE2E2', border: '#FECACA', activeBg: 'linear-gradient(90deg, #F87171, #DC2626)' };
};
const viewQuestion = (idx: number) => {
uni.navigateTo({
url: `/pages/doWork/index?recordId=${recordId.value}&reportFlag=1&idx=${idx}`,
});
};
onLoad((options: any) => {
recordId.value = options.id || '';
paperName.value = options.name ? decodeURIComponent(options.name) : '';
init();
});
const init = async () => {
pageLoading.value = true;
try {
const analyseRes = await getJobAnalyse({ recordId: recordId.value });
jobAnalyse.value = analyseRes.data || {};
const detailRes = await getPaperRecordDetail({
recordId: recordId.value,
reportFlag: 1,
});
paperList.value = detailRes.data?.subjectTitleVoList || [];
try {
const knowledgeRes = await getKnowledgeAnalyse({ recordId: recordId.value });
knowledgeList.value = knowledgeRes.data || [];
} catch (e) {
console.warn('[reports] knowledge err', e);
}
} catch (err) {
console.error('[reports] init err', err);
uni.showToast({ title: '加载失败', icon: 'none' });
} finally {
pageLoading.value = false;
}
};
</script>
<style lang="scss" scoped>
.rep-page {
min-height: 100vh;
background: #f5f7ff;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
}
.bg-decor {
position: absolute;
border-radius: 50%;
filter: blur(60rpx);
pointer-events: none;
z-index: 0;
&-a {
top: -100rpx;
left: -120rpx;
width: 360rpx;
height: 360rpx;
background: radial-gradient(circle, rgba(34, 197, 94, 0.3), transparent 70%);
}
&-b {
top: 280rpx;
right: -100rpx;
width: 320rpx;
height: 320rpx;
background: radial-gradient(circle, rgba(129, 140, 248, 0.35), transparent 70%);
}
&-c {
bottom: 80rpx;
left: -120rpx;
width: 320rpx;
height: 320rpx;
background: radial-gradient(circle, rgba(245, 158, 11, 0.25), transparent 70%);
}
}
/* Tabs */
.tab-bar {
padding: 12rpx 32rpx 0;
position: relative;
z-index: 1;
}
.tab-segment {
display: flex;
background: rgba(255, 255, 255, 0.7);
border-radius: 999rpx;
padding: 8rpx;
box-shadow: inset 0 4rpx 8rpx rgba(99, 102, 241, 0.1);
}
.tab-item {
flex: 1;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 999rpx;
color: #94a3b8;
font-size: 26rpx;
font-weight: 500;
transition: color 200ms ease;
&.active {
background: linear-gradient(180deg, #818cf8 0%, #4f46e5 100%);
color: #ffffff;
font-weight: 700;
box-shadow:
0 6rpx 14rpx rgba(79, 70, 229, 0.3),
inset 0 -3rpx 0 rgba(0, 0, 0, 0.12);
}
}
.rep-scroll {
flex: 1;
height: 0;
position: relative;
z-index: 1;
}
.tab-content {
padding: 24rpx 32rpx 0;
display: flex;
flex-direction: column;
gap: 28rpx;
}
/* Score Hero */
.score-hero {
position: relative;
border-radius: 36rpx;
padding: 36rpx 28rpx;
overflow: hidden;
box-shadow:
0 16rpx 32rpx rgba(99, 102, 241, 0.18),
inset 0 -6rpx 0 rgba(0, 0, 0, 0.05);
}
.score-hero-deco {
position: absolute;
inset: 0;
background:
radial-gradient(circle at 90% 20%, rgba(255, 255, 255, 0.6), transparent 50%),
radial-gradient(circle at 10% 90%, rgba(255, 255, 255, 0.3), transparent 50%);
}
.score-hero-content {
position: relative;
display: flex;
align-items: center;
gap: 28rpx;
}
.score-hero-circle {
flex-shrink: 0;
}
.score-ring {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow:
0 12rpx 24rpx rgba(0, 0, 0, 0.1),
inset 0 -4rpx 0 rgba(0, 0, 0, 0.05);
}
.score-ring-inner {
width: 152rpx;
height: 152rpx;
border-radius: 50%;
background: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow:
inset 0 6rpx 12rpx rgba(99, 102, 241, 0.08),
0 4rpx 8rpx rgba(0, 0, 0, 0.05);
}
.score-ring-num {
display: flex;
align-items: baseline;
gap: 2rpx;
.num {
font-size: 64rpx;
font-weight: 800;
color: #312e81;
line-height: 1;
}
.unit {
font-size: 24rpx;
font-weight: 700;
color: #6366f1;
}
}
.score-ring-label {
margin-top: 6rpx;
font-size: 22rpx;
color: #6366f1;
}
.score-hero-info {
flex: 1;
min-width: 0;
}
.paper-name {
font-size: 30rpx;
font-weight: 700;
color: #312e81;
line-height: 1.4;
margin-bottom: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.hero-row {
display: flex;
gap: 20rpx;
}
.hero-stat {
flex: 1;
padding: 16rpx;
background: rgba(255, 255, 255, 0.7);
border-radius: 20rpx;
backdrop-filter: blur(8rpx);
text-align: center;
.stat-num {
font-size: 28rpx;
font-weight: 800;
color: #312e81;
.stat-num-unit {
font-size: 18rpx;
font-weight: 600;
color: #94a3b8;
}
}
.stat-label {
font-size: 20rpx;
color: #6366f1;
margin-top: 4rpx;
}
}
/* Card 通用 */
.card {
background: #ffffff;
border-radius: 32rpx;
padding: 28rpx;
box-shadow:
0 12rpx 24rpx rgba(99, 102, 241, 0.12),
inset 0 -5rpx 0 rgba(199, 210, 254, 0.5);
}
.card-title {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 24rpx;
.title-bar {
width: 8rpx;
height: 28rpx;
border-radius: 4rpx;
background: linear-gradient(180deg, #818cf8, #4f46e5);
}
text {
font-size: 30rpx;
font-weight: 700;
color: #312e81;
}
}
/* 答题统计 */
.stat-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
}
.stat-card {
border-radius: 24rpx;
padding: 24rpx 12rpx;
text-align: center;
.stat-emoji {
width: 56rpx;
height: 56rpx;
line-height: 56rpx;
margin: 0 auto 12rpx;
border-radius: 50%;
font-size: 36rpx;
font-weight: 800;
color: #ffffff;
}
.stat-value {
font-size: 44rpx;
font-weight: 800;
line-height: 1;
}
.stat-tag {
margin-top: 8rpx;
font-size: 22rpx;
font-weight: 500;
}
&.correct {
background: linear-gradient(135deg, #dcfce7, #bbf7d0);
.stat-emoji {
background: linear-gradient(180deg, #4ade80, #16a34a);
box-shadow: 0 4rpx 12rpx rgba(22, 163, 74, 0.3);
}
.stat-value, .stat-tag { color: #15803d; }
}
&.wrong {
background: linear-gradient(135deg, #fee2e2, #fecaca);
.stat-emoji {
background: linear-gradient(180deg, #f87171, #dc2626);
box-shadow: 0 4rpx 12rpx rgba(220, 38, 38, 0.3);
}
.stat-value, .stat-tag { color: #b91c1c; }
}
&.unanswered {
background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
.stat-emoji {
background: linear-gradient(180deg, #94a3b8, #64748b);
box-shadow: 0 4rpx 12rpx rgba(100, 116, 139, 0.3);
}
.stat-value, .stat-tag { color: #475569; }
}
}
/* 饼图 */
.pie-row {
display: flex;
align-items: center;
gap: 24rpx;
}
.pie {
position: relative;
width: 200rpx;
height: 200rpx;
flex-shrink: 0;
}
.pie-circle {
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 0 8rpx 16rpx rgba(99, 102, 241, 0.12);
}
.pie-hole {
position: absolute;
inset: 28rpx;
border-radius: 50%;
background: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow:
inset 0 4rpx 8rpx rgba(0, 0, 0, 0.06),
0 2rpx 4rpx rgba(0, 0, 0, 0.04);
.pie-hole-num {
font-size: 44rpx;
font-weight: 800;
color: #312e81;
line-height: 1;
}
.pie-hole-label {
font-size: 20rpx;
color: #94a3b8;
margin-top: 4rpx;
}
}
.pie-legend {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.legend-item {
display: flex;
align-items: center;
gap: 12rpx;
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
flex-shrink: 0;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.legend-name {
flex: 1;
font-size: 24rpx;
color: #475569;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.legend-count {
font-size: 24rpx;
color: #4f46e5;
font-weight: 700;
}
}
/* 难度柱状图 */
.bars {
display: flex;
flex-direction: column;
gap: 18rpx;
}
.bar-row {
display: flex;
align-items: center;
gap: 16rpx;
}
.bar-name {
width: 80rpx;
flex-shrink: 0;
font-size: 24rpx;
color: #475569;
font-weight: 500;
}
.bar-track {
flex: 1;
height: 24rpx;
background: #f1f5f9;
border-radius: 999rpx;
overflow: hidden;
box-shadow: inset 0 2rpx 4rpx rgba(0, 0, 0, 0.06);
}
.bar-fill {
height: 100%;
border-radius: 999rpx;
transition: width 600ms ease-out;
box-shadow: inset 0 -2rpx 0 rgba(0, 0, 0, 0.1);
}
.bar-value {
width: 80rpx;
flex-shrink: 0;
text-align: right;
font-size: 26rpx;
font-weight: 700;
color: #312e81;
.bar-value-unit {
font-size: 18rpx;
color: #94a3b8;
margin-left: 2rpx;
font-weight: 500;
}
}
/* 题号网格 */
.qnum-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 16rpx;
}
.qnum-card {
aspect-ratio: 1;
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: transform 150ms ease;
&:active { transform: scale(0.92); }
.qnum-card-num {
font-size: 36rpx;
font-weight: 800;
line-height: 1;
}
.qnum-card-status {
margin-top: 4rpx;
font-size: 18rpx;
font-weight: 500;
}
&.correct {
background: linear-gradient(135deg, #dcfce7, #bbf7d0);
box-shadow: 0 4rpx 12rpx rgba(22, 163, 74, 0.18), inset 0 -3rpx 0 rgba(0, 0, 0, 0.05);
.qnum-card-num, .qnum-card-status { color: #15803d; }
}
&.wrong {
background: linear-gradient(135deg, #fee2e2, #fecaca);
box-shadow: 0 4rpx 12rpx rgba(220, 38, 38, 0.18), inset 0 -3rpx 0 rgba(0, 0, 0, 0.05);
.qnum-card-num, .qnum-card-status { color: #b91c1c; }
}
&.unanswered {
background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
box-shadow: 0 4rpx 12rpx rgba(100, 116, 139, 0.18), inset 0 -3rpx 0 rgba(0, 0, 0, 0.05);
.qnum-card-num, .qnum-card-status { color: #475569; }
}
}
.legend-card {
display: flex;
justify-content: center;
gap: 32rpx;
padding: 20rpx;
background: #ffffff;
border-radius: 24rpx;
box-shadow:
0 8rpx 16rpx rgba(99, 102, 241, 0.08),
inset 0 -3rpx 0 rgba(199, 210, 254, 0.5);
}
.legend-card-item {
display: flex;
align-items: center;
gap: 8rpx;
text {
font-size: 24rpx;
color: #475569;
}
}
.legend-mark {
width: 24rpx;
height: 24rpx;
border-radius: 8rpx;
&.correct {
background: linear-gradient(135deg, #4ade80, #16a34a);
}
&.wrong {
background: linear-gradient(135deg, #f87171, #dc2626);
}
&.unanswered {
background: linear-gradient(135deg, #94a3b8, #64748b);
}
}
/* 知识点 */
.knowledge-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.knowledge-item {
background: #ffffff;
border-radius: 24rpx;
padding: 24rpx;
box-shadow:
0 8rpx 16rpx rgba(99, 102, 241, 0.08),
inset 0 -3rpx 0 rgba(199, 210, 254, 0.5);
}
.knowledge-head {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 16rpx;
gap: 16rpx;
}
.knowledge-name {
flex: 1;
font-size: 28rpx;
font-weight: 600;
color: #312e81;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.knowledge-score {
flex-shrink: 0;
display: flex;
align-items: baseline;
.kn-num {
font-size: 36rpx;
font-weight: 800;
line-height: 1;
}
.kn-divider {
font-size: 24rpx;
color: #94a3b8;
margin: 0 4rpx;
}
.kn-total {
font-size: 24rpx;
color: #94a3b8;
}
}
.page-loader {
position: fixed;
inset: 0;
background: rgba(245, 247, 255, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 99;
}
</style>