fix(后台): SQL 测试点脚本读不出来时不能静默留一片空白编辑器

用浏览器把前后台走了一遍(这是第一次真的在界面上验证,之前全是脚本打 API)。
唯一找到的真问题在 SQLTestcaseEditor:

    onMounted(async () => {
      try { ... } catch {}     // ← 静默吞掉
    })

已有脚本读取失败时被 catch{} 吞掉,编辑器保持初始的 3 个空白项 ——
和「这题本来就没测试点」长得一模一样,教师完全看不出发生了什么。

改成:新题和旧格式测试点(404 problem-not-found / 409 not-sql-test-case)仍然
静默留空,那本来就是对的;其它失败挂一条 alert,并且把可操作的部分说全 ——
后端那句"测试点信息读取失败"只讲了现象,教师需要知道的是「下面是空模板、
直接存不会生效」。

保存本身是安全的,已实测:拿一道真实 SQL 题,在编辑器空白的状态下点提交,
test_case_id、测试点数(3)、sql_config 全部未变 —— 后端读不到测试点信息会
拒绝整个保存(400),不会把测试点清空。所以这条只是提示缺失,不是数据风险。

## 走查过程中的一次自我更正

中途我一度报告"保存返回 400 而界面没有任何错误提示",那是错的:提示是正常
显示的,我第一次等了 4 秒才检查,而 Naive UI 的提示 3 秒就自动消失了。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 05:19:23 -06:00
parent 516929461f
commit 34ae9b032c

View File

@@ -44,6 +44,8 @@ const refSQL = computed(
"", "",
) )
/** 已有脚本读取失败时的提示。空白编辑器和「本来就没测试点」长得一样,必须区分开 */
const loadError = ref("")
const isPreviewing = ref(false) const isPreviewing = ref(false)
const isUploading = ref(false) const isUploading = ref(false)
const isGenerating = ref(false) const isGenerating = ref(false)
@@ -79,7 +81,20 @@ onMounted(async () => {
if (res.data.length) { if (res.data.length) {
scripts.value = res.data.map((f) => ({ ...blankEntry(), sql: f.content })) scripts.value = res.data.map((f) => ({ ...blankEntry(), sql: f.content }))
} }
} catch {} } catch (err: any) {
// 新题、以及旧格式(非 SQL测试点后端回 404/409保持空白就是对的不该报错。
// 但**其它**失败必须说出来:读不出来时编辑器长得和「这题本来就没测试点」一模一样,
// 教师看不出区别,会以为要自己重新填。保存本身是安全的(后端读不到测试点信息会拒绝
// 整个保存),所以这里只提示、不阻塞。
const code = err?.error
if (code && code !== "problem-not-found" && code !== "not-sql-test-case") {
// 后端那句话(如"测试点信息读取失败")只说了现象,教师需要的是「下面是空的、别存」
const detail = err?.data ? `${err.data}` : ""
loadError.value =
`已有测试点脚本没能读出来${detail}。下方是空白模板,不是本题真实的测试点 —— ` +
`直接保存不会丢数据(后端会拒绝),但也不会生效。请先排查测试点文件,或重新上传。`
}
}
}) })
function add() { function add() {
@@ -195,6 +210,14 @@ async function upload() {
> >
还没有填写 SQL 标准答案请先在上方"本题参考答案"中填写再来编写测试点 还没有填写 SQL 标准答案请先在上方"本题参考答案"中填写再来编写测试点
</n-alert> </n-alert>
<n-alert
v-if="loadError"
type="error"
:show-icon="false"
style="margin-bottom: 8px"
>
{{ loadError }}
</n-alert>
<n-flex align="center" wrap> <n-flex align="center" wrap>
<n-button :disabled="isPreviewing || isGenerating" @click="reset"> <n-button :disabled="isPreviewing || isGenerating" @click="reset">
清空 清空