feat(后台): 手机上也能用了——菜单收进左边抽屉,列表一行一张卡,不用再横着滑

- 侧栏手机上不再占一列图标,顶栏左边 ☰ 拉出整张菜单,按返回键先关菜单
- 题目、比赛、用户、公告、题单列表手机上一项一张卡:名字一行、小字一行、按钮一行,
  「学生看得到」开关单独一列靠右
- 卡点分析、AI 报告手机上点开一项整屏看,返回键关掉;年度趋势、自学情况、首页改成上下排
- 出题页、教程编辑、题单编辑、标签、设置手机上排成一列;测试数据「删掉」手机上常驻
- 弹框一律收进屏幕宽度

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-16 11:21:58 +08:00
1 parent b757e2ac38
commit 02e2fa7d9b
30 files changed
+1328 -183

No files matched your search

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { useThemeVars } from "naive-ui"
import { useBreakpoints } from "shared/composables/breakpoints"
import { caseStatus, type AnswerSource, type CaseRow } from "./caseRows"
/**
@@ -14,6 +15,8 @@ const props = defineProps<{
}>()
const theme = useThemeVars()
// 手机上「当例子」那一列的表头藏了,勾选框自己带上字
const { isMobile } = useBreakpoints()
/** 输出最多先露这么多行,长了点开看全 */
const CLIP_LINES = 6
@@ -106,26 +109,30 @@ const status = (row: CaseRow) => caseStatus(row, props.source)
</div>
</template>
</div>
<n-checkbox
v-if="!examplesOnly"
v-model:checked="row.example"
class="example"
:aria-label="`第 ${index + 1} 组当例子`"
/>
<span class="mark" :class="status(row)">
<template v-if="status(row) === 'ok'">✓</template>
<template v-else-if="status(row) === 'error'">✗</template>
<template v-else-if="status(row) === 'changed'">●</template>
</span>
<n-button
quaternary
size="tiny"
class="remove"
:aria-label="`删掉第 ${index + 1} 组`"
@click="remove(index)"
>
删掉
</n-button>
<!-- 桌面上 display: contents,三样各占一格;手机上折到输入输出下面排成一行 -->
<div class="tools">
<n-checkbox
v-if="!examplesOnly"
v-model:checked="row.example"
class="example"
:aria-label="`第 ${index + 1} 组当例子`"
:label="isMobile ? '当例子' : undefined"
/>
<span class="mark" :class="status(row)">
<template v-if="status(row) === 'ok'">✓</template>
<template v-else-if="status(row) === 'error'">✗</template>
<template v-else-if="status(row) === 'changed'">●</template>
</span>
<n-button
quaternary
size="tiny"
class="remove"
:aria-label="`删掉第 ${index + 1} 组`"
@click="remove(index)"
>
删掉
</n-button>
</div>
</div>
</div>
</template>
@@ -254,4 +261,37 @@ const status = (row: CaseRow) => caseStatus(row, props.source)
.remove:focus-visible {
opacity: 1;
}
.tools {
display: contents;
}
/* 手机:一组占两行 —— 编号 / 输入 / 输出,下面一行 当例子 ✓ 删掉(没有悬停,删掉常显) */
@media (max-width: 768px) {
.row,
.examplesOnly .row {
grid-template-columns: 18px minmax(0, 1fr) minmax(0, 1fr);
gap: 6px;
}
.row.head > :nth-child(n + 4) {
display: none;
}
.tools {
grid-column: 2 / -1;
display: flex;
align-items: center;
gap: 10px;
}
.example {
margin-top: 0;
}
.remove {
margin-left: auto;
opacity: 1;
}
}
</style>