feat(流程图): 没走对的图,AI 对照答案说出错在哪个框、该怎么改,并把那个框标红
原来只有程序拼出的现象(「输出 a」输出的是 2,应该是 8),指的是出结果的框, 错的根子常在前面,学生和老师都看不出该改哪里。跑完以后再请 AI 看题目、图、 没走对的几组和老师的答案,写「哪里错了 / 可以这样改」两句,指出真正要改的框; 提交列表右栏的图和题目页画布上标红它。等级照旧只由跑出来的结果定, 点评失败或像代码就不要,退回只显示逐组结果。老提交不补。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8bd3d998ae
commit
d2fc0382ec
6 files changed
+256
-15
No files matched your search
@@ -10,6 +10,7 @@ import { parseTime } from "utils/functions"
|
||||
import { mermaidOrder, signature } from "shared/components/FlowchartEditor/model"
|
||||
import FlowchartCases from "shared/components/FlowchartCases.vue"
|
||||
import { caseHeadline, caseReport } from "utils/flowchart"
|
||||
import { useTone } from "shared/composables/tone"
|
||||
|
||||
/**
|
||||
* 「结果」页签里流程图作业的那一块:AI 在评 / 评完了几分 / 历次分数 / 评语和改进建议。
|
||||
@@ -39,6 +40,7 @@ watch(
|
||||
)
|
||||
const message = useMessage()
|
||||
const theme = useThemeVars()
|
||||
const tone = useTone()
|
||||
// 暗色主题的成功色是浅薄荷绿,上面的白字看不清
|
||||
const isDark = useDark()
|
||||
const passText = computed(() => (isDark.value ? "rgba(0, 0, 0, 0.85)" : "#fff"))
|
||||
@@ -160,9 +162,11 @@ watch(
|
||||
}
|
||||
const order = mermaidOrder(versionDoc.value)
|
||||
const toStep = (id: string) => order[Number(id.slice(1))]
|
||||
// 没走对的组标红 AI 指出的要改的框(错的根子),没有才退回程序找到的出结果的那个框
|
||||
const bad = row.ok ? null : (next?.focus ?? row.wrongAt)
|
||||
instance.setHighlight({
|
||||
order: row.path.map(toStep).filter((id): id is string => !!id),
|
||||
bad: row.wrongAt ? (toStep(row.wrongAt) ?? null) : null,
|
||||
bad: bad ? (toStep(bad) ?? null) : null,
|
||||
})
|
||||
},
|
||||
// 切回「结果」页签时组件重新挂载,这些值早就齐了,不会再变一次
|
||||
@@ -258,9 +262,22 @@ function goCode() {
|
||||
</n-flex>
|
||||
|
||||
<template v-if="detail && report">
|
||||
<!-- 没走对:AI 对着答案说的错在哪、怎么改,放在逐组结果前面(要改的框在画布上标红) -->
|
||||
<div
|
||||
v-if="report.passed < report.total && (detail.aiFeedback || detail.aiSuggestions)"
|
||||
class="review"
|
||||
>
|
||||
<div v-if="detail.aiFeedback">
|
||||
<div class="review-title">哪里错了</div>
|
||||
<p>{{ detail.aiFeedback }}</p>
|
||||
</div>
|
||||
<div v-if="detail.aiSuggestions">
|
||||
<div class="review-title">可以这样改</div>
|
||||
<p>{{ detail.aiSuggestions }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<FlowchartCases v-model:selected="selectedCase" :report="report" class="block" />
|
||||
<p v-if="detail.aiFeedback" class="tip">{{ detail.aiFeedback }}</p>
|
||||
<div v-if="detail.aiSuggestions" class="better">
|
||||
<div v-if="report.passed === report.total && detail.aiSuggestions" class="better">
|
||||
<div class="better-title">还可以更好</div>
|
||||
<p>{{ detail.aiSuggestions }}</p>
|
||||
</div>
|
||||
@@ -556,15 +573,26 @@ function goCode() {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.tip {
|
||||
.review {
|
||||
margin: 0 0 14px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(128, 128, 128, 0.08);
|
||||
background: v-bind("tone('error').background");
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.review-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.review p {
|
||||
margin: 2px 0 0;
|
||||
}
|
||||
|
||||
.better {
|
||||
margin-bottom: 14px;
|
||||
font-size: 14px;
|
||||
|
||||
@@ -89,6 +89,14 @@ async function load() {
|
||||
detail.value = res
|
||||
await nextTick()
|
||||
await renderFlowchart(graph.value, res.mermaidCode)
|
||||
markFocus(graph.value)
|
||||
}
|
||||
|
||||
/** AI 指出的要改的那个框标红。pele 把 Mermaid 的框号放在节点 <g> 的 data-id 上 */
|
||||
function markFocus(el: HTMLElement | null) {
|
||||
const focus = report.value?.focus
|
||||
if (!el || !focus) return
|
||||
el.querySelector(`.pele-node[data-id="${focus}"]`)?.classList.add("oj-focus")
|
||||
}
|
||||
|
||||
// 分开写三个来源:列表每次轮询都换一批新的行对象,一个 getter 返回数组的话回调次次都跑
|
||||
@@ -100,6 +108,7 @@ watch(bigOpen, async (open) => {
|
||||
if (!open || !detail.value) return
|
||||
await nextTick()
|
||||
await renderFlowchart(bigGraph.value, detail.value.mermaidCode)
|
||||
markFocus(bigGraph.value)
|
||||
})
|
||||
|
||||
const shown = computed(() => (detail.value?.id === props.row.id ? detail.value : null))
|
||||
@@ -129,6 +138,7 @@ function barColor(score: number, max: number) {
|
||||
|
||||
/** 2026-10 起的「走例子」报告;老提交是 null,照旧显示四项分 */
|
||||
const report = computed(() => caseReport(shown.value?.aiCriteriaDetails))
|
||||
const allPassed = computed(() => !!report.value && report.value.passed === report.value.total)
|
||||
const openCase = ref<number | null>(null)
|
||||
watch(
|
||||
() => shown.value?.id,
|
||||
@@ -258,9 +268,19 @@ const canRetry = computed(
|
||||
</template>
|
||||
<template v-else-if="shown && report">
|
||||
<b class="headline">{{ caseHeadline(report) }}</b>
|
||||
<!-- 没走对:AI 对着答案说的错在哪、怎么改,放在逐组结果前面(要改的框在左边图上标红) -->
|
||||
<div v-if="!allPassed && (shown.aiFeedback || shown.aiSuggestions)" class="review">
|
||||
<div v-if="shown.aiFeedback">
|
||||
<b>哪里错了</b>
|
||||
<p>{{ shown.aiFeedback }}</p>
|
||||
</div>
|
||||
<div v-if="shown.aiSuggestions">
|
||||
<b>可以这样改</b>
|
||||
<p>{{ shown.aiSuggestions }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<FlowchartCases v-model:selected="openCase" :report="report" />
|
||||
<div v-if="shown.aiFeedback" class="note">{{ shown.aiFeedback }}</div>
|
||||
<div v-if="shown.aiSuggestions" class="note">
|
||||
<div v-if="allPassed && shown.aiSuggestions" class="note">
|
||||
<b>还可以更好:</b>
|
||||
<div>{{ shown.aiSuggestions }}</div>
|
||||
</div>
|
||||
@@ -521,6 +541,29 @@ const canRetry = computed(
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 要改的框:压过 useMermaid 里按框类型上的色(那边也是 !important) */
|
||||
.graph :deep(.pele-node.oj-focus > :not(text)),
|
||||
.big-graph :deep(.pele-node.oj-focus > :not(text)) {
|
||||
fill: v-bind("tone('error').background") !important;
|
||||
stroke: v-bind("tone('error').solid") !important;
|
||||
stroke-width: 3px !important;
|
||||
}
|
||||
|
||||
.review {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
background: v-bind("tone('error').background");
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.review p {
|
||||
margin: 2px 0 0;
|
||||
}
|
||||
|
||||
.score-box {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
|
||||
@@ -26,6 +26,7 @@ export function caseReport(details: Record<string, unknown> | null | undefined)
|
||||
passed: cases.filter((row) => row.ok).length,
|
||||
total: cases.length,
|
||||
cases,
|
||||
focus: typeof details.focus === "string" ? details.focus : null,
|
||||
} satisfies FlowchartCaseReport
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user