fix(AI提示): 解锁条件前后端对齐,提示不再一点就没
Deploy / deploy (push) Has been cancelled

「失败 3 次解锁 AI 提示」实际是「在当前这次页面会话里再失败 3 次」:
problemStore.failCount 是个从 0 起数的内存计数器,刷新、切题、跳进跳出就归零,
而后端闸门数的是数据库里的历史失败数,两边根本不是一回事。昨天在这题上撞了
十次墙的学生今天进来照样看不到按钮。

- 数法收成一个 countFailedSubmissions(),题目详情的 myFailedCount 和
  POST /ai/hint 共用。原来详情把「等待/正在评分」也算失败,连点三次提交就能
  把按钮点亮,点下去却回 hint-locked
- 阈值 3 挪进契约 HINT_MIN_FAILURES,两端引用同一个常量
- failCount 改成 myFailedCount + 本次会话增量;在题目页里登录的补拉一次详情,
  否则停在匿名时的 0
- 结果面板改 display-directive="show",不再一收起来就把流式输出中的提示连同
  那次 LLM 调用一起作废;补「上次结果」按钮,原来唯一的重开方式是再提交一次
- prompt 里的判题结果翻成中文,原来拼的是裸状态码,模型不知道 -1 是什么
- system_error 不计入失败数、也不显示按钮:判题机自己崩了不是学生的问题
- 比赛中不给提示,和「求助」按钮同一个口径

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RC5uL72UY9aZFuTvUKe2jv
This commit is contained in:
2026-09-06 07:24:26 -06:00
co-authored by Claude Opus 5
parent 2e78b6efdf
commit bb0f5ec5ef
10 changed files with 172 additions and 34 deletions
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { Icon } from "@iconify/vue"
import { useThemeVars } from "naive-ui"
import { HINT_MIN_FAILURES } from "@oj2/contract"
import { JUDGE_STATUS, SubmissionStatus } from "utils/constants"
import {
submissionMemoryFormat,
@@ -54,19 +55,39 @@ const msg = computed(() => {
return msg
})
// 是否显示AI提示区域
// 是否显示AI提示区域
// 阈值和后端 POST /ai/hint 共用契约里的 HINT_MIN_FAILURES,别在这里写死数字;
// failCount 现在含服务端下发的历史失败数,刷新页面不会把进度清掉。
// system_error 也要排掉:那是判题机自己崩了,学生代码没毛病,让 AI 去分析
// 只会瞎编一通,后端的失败计数同样不认这个状态。
const showAIHint = computed(() => {
if (!props.submission) return false
// 比赛题不给提示,和「求助」按钮一致。用 problem.contestId 而不是路由参数:
// 带 contestId 的题目只可能从比赛入口进来(题库列表按 contest_id is null 过滤)。
if (problemStore.problem?.contestId != null) return false
return (
problemStore.failCount >= 3 &&
problemStore.failCount >= HINT_MIN_FAILURES &&
props.submission.result !== SubmissionStatus.accepted &&
props.submission.result !== SubmissionStatus.ast_check_failed &&
props.submission.result !== SubmissionStatus.system_error &&
props.submission.result !== SubmissionStatus.pending &&
props.submission.result !== SubmissionStatus.judging &&
props.submission.result !== SubmissionStatus.submitting
)
})
// 结果面板现在是 display-directive="show",关掉不再销毁组件,提示内容能留到重新打开。
// 代价是换了一次提交它也留着,所以这里按提交 id 手动清一次 —— 否则新结果底下挂着
// 上一次提交的提示,而且按钮已经被 v-if 藏了,学生没法重新分析。
watch(
() => props.submission?.id,
() => {
hintContent.value = ""
hintError.value = ""
hintLoading.value = false
},
)
async function fetchHint(submissionId: string) {
hintLoading.value = true
hintContent.value = ""