Files
OJ2/apps/web/src/oj/ai/components/StatStrip.vue
T
xuyueandClaude Opus 5.5 a5d5c39411 fix(手机): 收起键盘后「提交」按钮不回来;比赛领奖台第一名被挤出屏幕;iPhone 点输入框整页放大
- 题目页:安卓按返回键收键盘时编辑器不失焦,符号键一直贴底、「运行例子 / 提交」不回来。
  改成看键盘真弹着没有(可视视口变矮),不只看焦点
- 比赛排名:结束后的领奖台三块共 646px,手机上第一名被切掉、第三名看不见;改成平分一行
- iPhone:点 14/15px 的输入框和代码编辑器,Safari 会整页放大且不缩回;只给 iOS 加 maximum-scale=1
- 登录:手机上选完班不再自动聚焦搜索框(键盘弹出来盖住半张名单)
- 题单:窄屏上题目拆成两张没标题的卡片,像分了两组;放不下两栏时合成一张
- 「中等」在题目页是蓝色、在题目列表是橙色,统一成橙色
- 零碎:自学四列表格在 360 宽上收窄格子;统计「错得最多的题」表头不再挤成竖排;
  「第 N 名」「14 道」不再把最后一个字甩到下一行

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:36:33 +08:00

115 lines
2.6 KiB
Vue

<script setup lang="ts">
import type { LearningReport } from "@oj2/contract"
import { useThemeVars } from "naive-ui"
/** 顶上一排数:做对几道、一次就对、上了几节课、差一点的;老师看时最前面多一格「班上第几」 */
const props = defineProps<{ report: LearningReport; teacher: boolean; compact?: boolean }>()
const theme = useThemeVars()
interface Cell {
big: number
unit: string
sub: string
warn?: boolean
}
const cells = computed(() => {
const r = props.report
const c = r.classStats
const percent = r.solved ? Math.round((r.firstTry / r.solved) * 100) : 0
const firstSub = `一次就对 · 占 ${percent}%`
const list: Cell[] = [
// 数和「道」之间用不换行空格:手机上两列挤,单个「道」会被甩到下一行
{
big: r.solved,
unit: "道",
sub: c ? `做对 · 班上中间那位 ${c.medianSolved}\u00a0道` : "做对",
},
{
big: r.firstTry,
unit: "道",
sub: c && !props.compact ? `${firstSub},班上中间那位 ${c.medianFirstPercent}%` : firstSub,
},
{ big: r.lessonCount, unit: "节课", sub: `交了 ${r.submissionCount} 次` },
]
if (r.unsolved.length)
list.push({ big: r.unsolved.length, unit: "道", sub: "差一点 · 交过还没做对", warn: true })
if (props.teacher && c)
list.unshift({ big: c.rank, unit: `/ ${c.size}`, sub: "班上按做对题数排第几" })
return list
})
</script>
<template>
<div class="strip" :class="{ compact }">
<div v-for="cell in cells" :key="cell.sub" class="cell">
<div class="num">
<b :class="{ warn: cell.warn }">{{ cell.big }}</b>
<span>{{ cell.unit }}</span>
</div>
<div class="sub">{{ cell.sub }}</div>
</div>
</div>
</template>
<style scoped>
.strip {
display: flex;
border: 1px solid v-bind("theme.borderColor");
border-radius: var(--oj-radius);
background: v-bind("theme.cardColor");
}
.cell {
flex: 1;
min-width: 0;
padding: 14px 20px;
border-left: 1px solid v-bind("theme.dividerColor");
}
.cell:first-child {
border-left: 0;
}
.num {
display: flex;
align-items: baseline;
gap: 4px;
}
.num b {
font-size: 30px;
line-height: 38px;
font-variant-numeric: tabular-nums;
}
.num b.warn {
color: #c27c0e;
}
.num span {
font-size: var(--oj-fs-body);
}
.sub {
font-size: var(--oj-fs-meta);
color: v-bind("theme.textColor3");
}
.compact {
display: grid;
grid-template-columns: 1fr 1fr;
}
.compact .cell {
padding: 10px 12px;
border-left: 0;
}
.compact .num b {
font-size: 26px;
line-height: 32px;
}
</style>