fix(题目统计): 「答案错误几乎都卡在第 1 个测试点」几乎每道题都弹,说了等于没说——答案错误最多时不再给提示
Deploy / deploy (push) Canceled after 0s

七成多的题错得最多的都是答案错误(快照 349 / 484),卡在第 1 个测试点过六成的也有 185 / 320 道,
两句提示对哪道题都一样。具体错在哪,每次提交的结果里已经有「题目里的例子 N 就错了」和三栏对照。
运行时错误、编译失败排第一时的提示保留。后端那条扫 info JSONB 数第 1 个点的查询一起删掉。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-09-30 12:21:00 +08:00
1 parent c22521fb61
commit a8918b41b1
3 files changed
+12 -25

No files matched your search

+2 -14
View File
@@ -5,7 +5,7 @@ import { Hono } from "hono"
import { optionalAuth, type AppEnv } from "../auth/middleware"
import { db, schema } from "../db"
import { failure, success } from "../http"
import { JudgeStatus, UNJUDGED_RESULTS, type JudgeStatusValue } from "../judge/status"
import { UNJUDGED_RESULTS, type JudgeStatusValue } from "../judge/status"
import { canAccessContest, contestDetailsAllowed, findAccessibleContest } from "../services/contest"
import { accepted } from "../services/learning-stats"
import { isAdminRole, isTeacherOrAbove, queryInteger } from "./helpers"
@@ -18,7 +18,6 @@ const EMPTY: ProblemStats = {
solved: 0,
tries: { one: 0, few: 0, many: 0 },
failures: [],
wrongAnswerFirstCase: 0,
me: null,
myClass: null,
classes: null,
@@ -78,7 +77,7 @@ problemStatsRoutes.get("/problems/:id/stats", optionalAuth, async (c) => {
sql`, `,
)
// 每人一行:窗口函数先给每条提交标上这个人第一次做对的时刻,再按人数到那一刻为止交了几次
const [users, failureRows, firstCase] = await Promise.all([
const [users, failureRows] = await Promise.all([
db.execute<UserRow>(sql`
select s.user_id, u.username, u.class_name,
count(*)::int as attempts,
@@ -103,16 +102,6 @@ problemStatsRoutes.get("/problems/:id/stats", optionalAuth, async (c) => {
and s.result not in (${unjudgedList})
group by u.class_name, s.result
`),
// 判题机按测试点回一个数组,test_case 是 "1"、"2"……
db.execute<{ n: number }>(sql`
select count(*)::int as n from ${schema.submission}
where problem_id = ${problem.id} and result = ${JudgeStatus.WRONG_ANSWER}
and jsonb_typeof(info->'data') = 'array'
and exists (
select 1 from jsonb_array_elements(info->'data') e
where e->>'test_case' = '1' and (e->>'result')::int <> 0
)
`),
])
const solvedUsers = users.filter((row) => row.solved)
@@ -142,7 +131,6 @@ problemStatsRoutes.get("/problems/:id/stats", optionalAuth, async (c) => {
solved: solvedUsers.length,
tries,
failures: sortFailures(siteFailures),
wrongAnswerFirstCase: firstCase[0]?.n ?? 0,
me: user ? { attempts: mine?.attempts ?? 0, solved: mine?.solved ?? false } : null,
myClass: myClassName
? {
@@ -103,16 +103,17 @@ const failedTotal = computed(() =>
)
const topFailures = computed(() => (stats.value?.failures ?? []).slice(0, 3))
/** 错得最多的那一种,给一句该怎么办。都指向「运行例子」:提交前自己就能看出来 */
/**
* 错得最多的那一种,给一句该怎么办。都指向「运行例子」:提交前自己就能看出来。
*
* **答案错误最多时不给**:七成多的题错得最多的都是答案错误(快照 349 / 484),「卡在第 1 个
* 测试点」也是常态(320 道里 185 道过 60%),这句话几乎每道题都一样,等于没说(用户说的)。
* 具体错在哪,每次提交的结果里有「题目里的例子 N 就错了」和三栏对照。
* 运行时错误、编译失败排第一的题少,出现了才说明这题有特点
*/
const tip = computed(() => {
const s = stats.value
const top = s?.failures[0]
if (!s || !top) return ""
if (top.result === -1) {
return s.wrongAnswerFirstCase >= top.count * 0.6
? "答案错误几乎都卡在第 1 个测试点:多半是例子都没对上。先点「运行例子」,把你的输出和例子一行一行对一对。"
: "答案错误最多:输出和标准答案对不上。留意空格、换行和标点,交之前先点「运行例子」对一对。"
}
const top = stats.value?.failures[0]
if (!top) return ""
if (top.result === 4) {
return "运行时错误最多:程序跑到一半出错了。交之前先点「运行例子」,看看有没有红色的报错。"
}
-2
View File
@@ -464,8 +464,6 @@ export const problemStatsSchema = z.object({
tries: z.object({ one: z.number().int(), few: z.number().int(), many: z.number().int() }),
/** 没通过的提交按结果分,多的在前(不含判题中) */
failures: z.array(failureCountSchema),
/** 答案错误里第 1 个测试点就没过的条数 —— 多半是例子都没对上,提示先点「运行例子」 */
wrongAnswerFirstCase: z.number().int(),
/** 我自己:交了几次、做对没有。没登录为 null */
me: z.object({ attempts: z.number().int(), solved: z.boolean() }).nullable(),
/** 学生自己班这题 x / y 人做对(y 是班里交过的人)。没班级、比赛里为 null */