diff --git a/apps/web/src/admin/problem/detail.vue b/apps/web/src/admin/problem/detail.vue
index d07645a..b2b9cce 100644
--- a/apps/web/src/admin/problem/detail.vue
+++ b/apps/web/src/admin/problem/detail.vue
@@ -173,6 +173,16 @@ const languageOptions = [
const isSQLProblem = computed(() => !!problem.value?.languages.includes("SQL"))
// SQL 题联动:SQL 必须是唯一语言(后端强校验),不需要预制代码,自动初始化 sql_config
+// 两个流程图开关是互斥的:allowFlowchart 为真时后端不会把 mermaidCode 下发给
+// 学生,showFlowchart 就成了一个点进去什么都没有的 tab。UI 上已经把开关置灰,
+// 这里再把存量数据里两个都开着的情况纠正掉。
+watch(
+ () => problem.value?.allowFlowchart,
+ (allow) => {
+ if (allow) problem.value.showFlowchart = false
+ },
+)
+
watch(
() => problem.value?.languages,
(langs) => {
@@ -310,9 +320,10 @@ function downloadTestcases() {
download(`problems/${problem.value.id}/test-cases`)
}
-// Mermaid 渲染事件处理
-function onMermaidRenderSuccess() {
- mermaidRenderSuccess.value = true
+// Mermaid 渲染事件处理。这里必须原样接受 false ——
+// 原来只在成功时置 true、永不复位,先写对再改坏就能把语法错误的代码存进库
+function onMermaidRenderState(ok: boolean) {
+ mermaidRenderSuccess.value = ok
}
// 题目是否有漏写的
@@ -864,7 +875,15 @@ watch(
-
+
+
+
+ 让学生自己画图时,标准流程图不会下发给学生,这个开关没有意义
+
+
@@ -872,7 +891,7 @@ watch(
diff --git a/apps/web/src/oj/problem/detail.vue b/apps/web/src/oj/problem/detail.vue
index c8a20eb..d0047ac 100644
--- a/apps/web/src/oj/problem/detail.vue
+++ b/apps/web/src/oj/problem/detail.vue
@@ -53,9 +53,17 @@ const { shouldShowProblem } = storeToRefs(screenModeStore)
const { isMobile, isDesktop } = useBreakpoints()
+// tab 选项和面板必须用同一个条件。后端在 allowFlowchart 为真时会把 mermaidCode
+// 置成 null(不能把标准答案下发给正要自己画图的学生),只看 showFlowchart 的话,
+// 两个开关同时打开就会做出一个「选项存在、面板不存在」的 tab —— URL 里带
+// ?tab=flowchart 会选中一个渲染不出任何东西的页签。
+const canShowFlowchart = computed(
+ () => !!problem.value?.showFlowchart && !!problem.value?.mermaidCode,
+)
+
const tabOptions = computed(() => {
const options: string[] = ["content"]
- if (problem.value?.showFlowchart) {
+ if (canShowFlowchart.value) {
options.push("flowchart")
}
@@ -159,7 +167,7 @@ watch(
@@ -211,7 +219,7 @@ watch(
@@ -251,7 +259,7 @@ watch(
-
+
diff --git a/apps/web/src/shared/components/MermaidEditor.vue b/apps/web/src/shared/components/MermaidEditor.vue
index 7c042a3..34e79b3 100644
--- a/apps/web/src/shared/components/MermaidEditor.vue
+++ b/apps/web/src/shared/components/MermaidEditor.vue
@@ -7,19 +7,26 @@ const mermaidContainer = useTemplateRef("mermaidContainer")
const { renderFlowchart, renderError, renderSuccess } = useMermaid()
+// 上报渲染结果而不是只上报成功:调用方拿它做保存前校验,只进不出的话,
+// 「先写对再改坏」照样能存进库
const emit = defineEmits<{
- renderSuccess: []
+ renderState: [ok: boolean]
}>()
const renderMermaid = async () => {
await renderFlowchart(mermaidContainer.value, modelValue.value)
- if (renderSuccess.value) emit("renderSuccess")
+ emit("renderState", renderSuccess.value)
}
onMounted(() => {
nextTick(renderMermaid)
})
+// 一改动就立刻把状态打回「未验证」,等防抖后的渲染真跑完再报结果。
+// 只挂防抖那一支的话,改完 300ms 内点保存,读到的还是上一次渲染的结论 ——
+// 刚改坏的代码会被当成校验通过。宁可让用户多等一下,也不能放脏数据进库。
+watch(modelValue, () => emit("renderState", false))
+
// 出题页是边敲边预览,不防抖的话每个字符都会触发一次完整的 mermaid 渲染,
// 而中间态几乎全是语法错误
watchDebounced(modelValue, renderMermaid, { debounce: 300, maxWait: 1000 })