refactor(前端): shared / utils 不再 import oj 和 admin 下的任何东西

依赖方向原来是反的:顶栏、登录框、举手列表这些 shared 组件从 oj/ 里拿东西。
- 跨端的接口挪进 shared/api.ts(按 apps/web/CLAUDE.md 的分法):学生端题目列表、
  出题人列表、这节课的题、待弹的成就
- 这节课的 store → shared/store/lesson.ts;头像 RankAvatar → shared/components
- 纯函数挪进 utils/:举手列表的错法归类 errorKind、它依赖的答案错误分类 wrongAnswer
  和 Python 报错翻译 pythonError、题目列表行的 toProblemRow
- 只有后台在用的出题人下拉 AuthorSelect 挪回 admin/components

纯搬家。首页、题目列表、题目页、排名、课堂看板、后台题目列表打开无报错,
顶栏题号框敲 1001 回车直达题目页。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-16 15:11:21 +08:00
1 parent d4aadc7722
commit e8a20d12f9
38 files changed
+78 -78

No files matched your search

+42 -2
View File
@@ -1,8 +1,16 @@
import type { LoginRequest, RegisterRequest } from "@oj2/contract"
import type { Quote, WebsiteConfig } from "@oj2/contract"
import type {
ClassActivity,
MarkAchievementsRead,
ProblemAuthor,
ProblemList,
Quote,
WebsiteConfig,
} from "@oj2/contract"
import api from "utils/api"
import { contractDeferred } from "utils/contract"
import type { Profile, Tag } from "utils/types"
import { toProblemRow } from "utils/transforms"
import type { PendingAchievement, Profile, Tag } from "utils/types"
export function login(data: { username: string; password: string }) {
return api.post("auth/login", data satisfies LoginRequest)
@@ -51,3 +59,35 @@ export function getClassUsernames(classroom: string) {
export function getWebsiteConfig() {
return api.get<WebsiteConfig>("site")
}
export async function getProblemList(
offset = 0,
limit = 10,
searchParams: Record<string, unknown> = {},
) {
const res = await api.get<ProblemList>("problems", {
params: { paging: true, offset, limit, ...searchParams },
})
return {
results: res.results.map(toProblemRow),
total: res.total,
}
}
export function getAuthors(all = false) {
return api.get<ProblemAuthor[]>("problem-authors", {
params: { all: all ? "1" : "0" },
})
}
export function getClassActivity() {
return api.get<ClassActivity>("me/class-activity")
}
export function getPendingAchievements() {
return api.get<PendingAchievement[]>("achievements/pending")
}
export function markAchievementsRead(ids: number[]) {
return api.post("achievements/pending/read", { ids } satisfies MarkAchievementsRead)
}