refactor: 刷题中心纯div行收敛到AppStack

This commit is contained in:
liyy 2026-09-03 17:53:50 +08:00
parent e4a890d9a1
commit c20010d9dd

View File

@ -209,13 +209,13 @@ const subtitle = computed(() => {
:class="{ 'module-card--active': activeModule === m.name }" :class="{ 'module-card--active': activeModule === m.name }"
@click="selectModule = m.name" @click="selectModule = m.name"
> >
<div class="module-card__row"> <AppStack direction="row" class="module-card__row">
<span class="module-card__name">{{ m.name }}</span> <span class="module-card__name">{{ m.name }}</span>
<span v-if="activeModule === m.name" class="module-card__check"> <span v-if="activeModule === m.name" class="module-card__check">
<AppIcon name="check" :size="14" /> <AppIcon name="check" :size="14" />
</span> </span>
</div> </AppStack>
<div class="module-card__meta"> <AppStack direction="row" gap="space-1" class="module-card__meta">
<span class="module-card__count">{{ m.total }} </span> <span class="module-card__count">{{ m.total }} </span>
<span class="module-card__dot">·</span> <span class="module-card__dot">·</span>
<span <span
@ -224,7 +224,7 @@ const subtitle = computed(() => {
> >
掌握度 {{ formatPercent(masteryByModule.get(m.name) ?? 0) }} 掌握度 {{ formatPercent(masteryByModule.get(m.name) ?? 0) }}
</span> </span>
</div> </AppStack>
</button> </button>
</div> </div>
<AppEmpty v-if="(modules.data.value?.modules.length ?? 0) === 0" title="还没有题目" description="请先到题库管理导入题目,再开始刷题。"> <AppEmpty v-if="(modules.data.value?.modules.length ?? 0) === 0" title="还没有题目" description="请先到题库管理导入题目,再开始刷题。">
@ -260,10 +260,10 @@ const subtitle = computed(() => {
<AppEmpty v-if="reasons.length === 0" icon="chart" title="暂无错因数据" description="完成刷题后根据错题统计错因分布。" /> <AppEmpty v-if="reasons.length === 0" icon="chart" title="暂无错因数据" description="完成刷题后根据错题统计错因分布。" />
<div v-else class="reason-bars"> <div v-else class="reason-bars">
<div v-for="r in reasons" :key="r.reason" class="reason-bar"> <div v-for="r in reasons" :key="r.reason" class="reason-bar">
<div class="reason-bar__row"> <AppStack direction="row" class="reason-bar__row">
<span class="reason-bar__label">{{ r.reason }}</span> <span class="reason-bar__label">{{ r.reason }}</span>
<span class="reason-bar__pct">{{ formatPercent(r.percent) }}</span> <span class="reason-bar__pct">{{ formatPercent(r.percent) }}</span>
</div> </AppStack>
<div class="reason-bar__track"> <div class="reason-bar__track">
<div class="reason-bar__fill" :style="{ width: `${r.percent}%` }" /> <div class="reason-bar__fill" :style="{ width: `${r.percent}%` }" />
</div> </div>
@ -282,15 +282,15 @@ const subtitle = computed(() => {
class="pending-item" class="pending-item"
:to="{ name: 'practice-wrong' }" :to="{ name: 'practice-wrong' }"
> >
<div class="pending-item__meta"> <AppStack direction="row" gap="space-2" class="pending-item__meta">
<span class="pending-item__module">{{ item.module }}</span> <span class="pending-item__module">{{ item.module }}</span>
<span class="pending-item__sub">{{ item.subModule }}</span> <span class="pending-item__sub">{{ item.subModule }}</span>
</div> </AppStack>
<div class="pending-item__text">{{ item.stem }}</div> <div class="pending-item__text">{{ item.stem }}</div>
<div class="pending-item__foot"> <AppStack direction="row" class="pending-item__foot">
<span class="pending-item__reason">{{ item.wrongReason }}</span> <span class="pending-item__reason">{{ item.wrongReason }}</span>
<span class="pending-item__count">已复习 {{ item.reviewCount }} </span> <span class="pending-item__count">已复习 {{ item.reviewCount }} </span>
</div> </AppStack>
</RouterLink> </RouterLink>
</div> </div>
</AppCard> </AppCard>
@ -372,13 +372,13 @@ const subtitle = computed(() => {
class="wrong-book-item" class="wrong-book-item"
:to="{ name: 'practice-wrong-detail', params: { id: item.id } }" :to="{ name: 'practice-wrong-detail', params: { id: item.id } }"
> >
<div class="wrong-book-item__head"> <AppStack direction="row" gap="space-2" class="wrong-book-item__head">
<div class="wrong-book-item__tags"> <div class="wrong-book-item__tags">
<AppBadge variant="primary">{{ item.module }}</AppBadge> <AppBadge variant="primary">{{ item.module }}</AppBadge>
<AppBadge v-if="item.subModule" variant="soft">{{ item.subModule }}</AppBadge> <AppBadge v-if="item.subModule" variant="soft">{{ item.subModule }}</AppBadge>
</div> </div>
<AppBadge :variant="wrongStatusVariant(item.status)">{{ wrongStatusLabel(item.status) }}</AppBadge> <AppBadge :variant="wrongStatusVariant(item.status)">{{ wrongStatusLabel(item.status) }}</AppBadge>
</div> </AppStack>
<p class="wrong-book-item__stem">{{ item.stem }}</p> <p class="wrong-book-item__stem">{{ item.stem }}</p>
<div class="wrong-book-item__foot"> <div class="wrong-book-item__foot">
<span v-if="item.wrongReason" class="wrong-book-item__reason">错因 · {{ item.wrongReason }}</span> <span v-if="item.wrongReason" class="wrong-book-item__reason">错因 · {{ item.wrongReason }}</span>
@ -462,9 +462,8 @@ const subtitle = computed(() => {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 14%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 14%, transparent);
} }
.module-card__row { .module-card__row {
display: flex; --stack-align: center;
align-items: center; --stack-justify: space-between;
justify-content: space-between;
} }
.module-card__name { .module-card__name {
font-size: var(--fs-card-title); font-size: var(--fs-card-title);
@ -481,9 +480,7 @@ const subtitle = computed(() => {
color: var(--on-accent); color: var(--on-accent);
} }
.module-card__meta { .module-card__meta {
display: flex; --stack-align: center;
align-items: center;
gap: var(--space-1);
font-size: var(--fs-label); font-size: var(--fs-label);
color: var(--text-secondary); color: var(--text-secondary);
} }
@ -531,9 +528,8 @@ const subtitle = computed(() => {
gap: var(--space-3); gap: var(--space-3);
} }
.reason-bar__row { .reason-bar__row {
display: flex; --stack-align: center;
align-items: center; --stack-justify: space-between;
justify-content: space-between;
margin-bottom: var(--space-1); margin-bottom: var(--space-1);
font-size: var(--fs-subtitle); font-size: var(--fs-subtitle);
} }
@ -579,9 +575,7 @@ const subtitle = computed(() => {
padding-block: var(--space-1); padding-block: var(--space-1);
} }
.pending-item__meta { .pending-item__meta {
display: flex; --stack-align: center;
align-items: center;
gap: var(--space-2);
font-size: var(--fs-label); font-size: var(--fs-label);
} }
.pending-item__module { .pending-item__module {
@ -601,9 +595,8 @@ const subtitle = computed(() => {
overflow: hidden; overflow: hidden;
} }
.pending-item__foot { .pending-item__foot {
display: flex; --stack-align: center;
align-items: center; --stack-justify: space-between;
justify-content: space-between;
font-size: var(--fs-label); font-size: var(--fs-label);
color: var(--text-secondary); color: var(--text-secondary);
} }
@ -679,10 +672,8 @@ const subtitle = computed(() => {
box-shadow: var(--shadow-level-1); box-shadow: var(--shadow-level-1);
} }
.wrong-book-item__head { .wrong-book-item__head {
display: flex; --stack-align: center;
align-items: center; --stack-justify: space-between;
justify-content: space-between;
gap: var(--space-2);
} }
.wrong-book-item__tags { .wrong-book-item__tags {
display: flex; display: flex;