feat(前台): 顶栏可以输入题号直达;首页列出班里最近一次课一起做的题和自己的完成情况
Deploy / deploy (push) Canceled after 0s

课上老师报题号、全班去找,是 2025 秋七成非比赛提交的来路,界面上原本没有它的入口。

- 顶栏(桌面端)加题号框,首页「找题」同一套逻辑:题号对上直接进题,否则去列表搜
- 新接口 GET /me/class-activity:同班同一天 ≥5 人做过的题,取最近 7 天里最近的一天,
  附带我自己的状态与班里通过人数;首页据此显示「今天班里在做」卡片,没有就不占位

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-09-27 20:58:15 +08:00
1 parent d07459928d
commit 039992dc86
7 files changed
+279 -8

No files matched your search

+29
View File
@@ -4,6 +4,7 @@ import { RouterLink } from "vue-router"
import { useBreakpoints } from "shared/composables/breakpoints"
import { useDarkTransition } from "shared/composables/darkTransition"
import { useLearnProgress } from "shared/composables/learnProgress"
import { useProblemJump } from "shared/composables/problemJump"
import { useAuthModalStore } from "shared/store/authModal"
import { useCollabStore } from "shared/store/collab"
import { useScreenModeStore } from "shared/store/screenMode"
@@ -62,6 +63,18 @@ function getRandomAvatar() {
const avatar = ref(getRandomAvatar())
/**
* 顶栏的题号框:老师报完题号,学生在哪一页都能直接敲,不用先回首页或题目列表。
* 只给桌面端 —— 窄屏顶栏已经挤满了,手机上从首页的搜索框走同一套逻辑。
*/
const { jump, jumping } = useProblemJump()
const jumpKeyword = ref("")
async function handleJump() {
await jump(jumpKeyword.value)
jumpKeyword.value = ""
}
const envVersion = computed(() => {
if (import.meta.env.PUBLIC_ENV === "test") {
return "测试版"
@@ -263,6 +276,18 @@ function goHome() {
<span style="padding-left: 8px">菜单</span>
</n-button>
</n-dropdown>
<n-input
v-if="isDesktop"
v-model:value="jumpKeyword"
class="jump"
placeholder="输入题号直达"
:loading="jumping"
@keyup.enter="handleJump"
>
<template #prefix>
<Icon icon="ph:magnifying-glass" />
</template>
</n-input>
<n-button
v-if="isDesktop && (route.name === 'problem' || route.name === 'contest problem')"
@click="() => screenModeStore.switchScreenMode()"
@@ -305,4 +330,8 @@ function goHome() {
.title {
font-size: 18px;
}
.jump {
width: 160px;
}
</style>
@@ -0,0 +1,27 @@
import { getProblemList } from "oj/api"
/**
* 按题号直达。课上老师报一个题号、全班去找,是非比赛提交最主要的来路,
* 所以敲完题号回车就该进题,而不是先落到列表再点一下。
*
* 题号对上了(不分大小写)才直达;对不上、或者敲的是题目名,就去列表搜 ——
* 列表那边的 keyword 是题号和标题一起模糊匹配,这里只是在它前面加了一步。
*/
export function useProblemJump() {
const router = useRouter()
const jumping = ref(false)
async function jump(input: string) {
const keyword = input.trim()
if (!keyword) return router.push("/problem")
jumping.value = true
// 查询失败就当没对上,照样去列表搜,别让一次网络抖动把回车吞掉
const res = await getProblemList(0, 20, { keyword }).catch(() => null)
jumping.value = false
const exact = res?.results.find((row) => row._id.toLowerCase() === keyword.toLowerCase())
if (exact) return router.push(`/problem/${exact._id}`)
return router.push({ path: "/problem", query: { keyword } })
}
return { jump, jumping }
}