AI 是按分值从高到低返回的:`逻辑正确性(40) → 完整性(30) → 规范性(20) → 清晰度(10)`。 但 `ai_criteria_details` 存在 jsonb 列里,而 Postgres 的 jsonb **不保留键序** —— 它按「键长度 + 字节序」重排,读出来变成 `完整性 → 清晰度 → 规范性 → 逻辑正确性`, 权重最高的那项被排到了最后。 评分弹框和教师端的评分详情都是直接 `v-for` 遍历这个对象,所以两处都乱。 统计面板因为用的是写死的 `CRITERIA_ORDER`,一直是对的 —— 于是同一份数据在两个 地方的顺序还不一致。 把顺序抽到 `utils/constants` 共享,三处统一走 `sortFlowchartCriteria()`; 表里没有的键排到后面,AI 万一返回别的评分项也不会丢。 顺带把限流的提示改得能看懂:撞上 429 时原来只显示「流程图提交失败」,学生会以为 是自己的图有问题然后反复点,越点等得越久。现在按错误码分支,提示「提交太频繁了, 缓一会儿再交」。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { toRefs } from "vue"
|
||||
|
||||
// 工具函数
|
||||
import { atou, utoa } from "utils/functions"
|
||||
import { sortFlowchartCriteria } from "utils/constants"
|
||||
|
||||
// 组合式函数
|
||||
import { useBreakpoints } from "shared/composables/breakpoints"
|
||||
@@ -79,6 +80,11 @@ const suggestionLines = computed(() =>
|
||||
splitSuggestionLines(evaluation.value.suggestions),
|
||||
)
|
||||
|
||||
// jsonb 不保留键序,直接遍历会把 40 分的「逻辑正确性」排到最后
|
||||
const sortedCriteria = computed(() =>
|
||||
sortFlowchartCriteria(evaluation.value.criteria_details),
|
||||
)
|
||||
|
||||
function splitSuggestionLines(suggestions?: string | null) {
|
||||
return suggestions
|
||||
? suggestions
|
||||
@@ -251,9 +257,17 @@ async function submitFlowchartData() {
|
||||
}
|
||||
|
||||
message.success("流程图已提交,请耐心等待评分")
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
loading.value = false
|
||||
message.error("流程图提交失败")
|
||||
// 按错误码分支(见 utils/api.ts 的约定)。限流是最容易撞上的一种:
|
||||
// 只说「提交失败」的话,学生会以为是自己的图有问题,然后反复点,越点越久
|
||||
if (error?.error === "too-many-submissions") {
|
||||
message.warning("提交太频繁了,缓一会儿再交")
|
||||
} else if (error?.error === "flowchart-not-allowed") {
|
||||
message.error("这道题不接受流程图提交")
|
||||
} else {
|
||||
message.error("流程图提交失败")
|
||||
}
|
||||
console.error("提交流程图失败:", error)
|
||||
}
|
||||
}
|
||||
@@ -496,12 +510,12 @@ onUnmounted(() => {
|
||||
|
||||
<!-- 详细评分 -->
|
||||
<n-card
|
||||
v-if="evaluation.criteria_details"
|
||||
v-if="sortedCriteria.length"
|
||||
size="small"
|
||||
title="详细评分"
|
||||
>
|
||||
<div
|
||||
v-for="(detail, key) in evaluation.criteria_details"
|
||||
v-for="[key, detail] in sortedCriteria"
|
||||
:key="key"
|
||||
style="margin-bottom: 12px"
|
||||
>
|
||||
|
||||
@@ -70,12 +70,12 @@
|
||||
|
||||
<!-- 详细评分 -->
|
||||
<n-card
|
||||
v-if="Object.keys(criteriaDetails).length > 0"
|
||||
v-if="sortedCriteria.length > 0"
|
||||
size="small"
|
||||
title="详细评分"
|
||||
>
|
||||
<div
|
||||
v-for="(detail, key) in criteriaDetails"
|
||||
v-for="[key, detail] in sortedCriteria"
|
||||
:key="key"
|
||||
style="margin-bottom: 12px"
|
||||
>
|
||||
@@ -109,6 +109,7 @@
|
||||
import { Icon } from "@iconify/vue"
|
||||
import type { FlowchartSubmission } from "utils/types"
|
||||
import { useMermaid } from "shared/composables/useMermaid"
|
||||
import { sortFlowchartCriteria } from "utils/constants"
|
||||
|
||||
interface Props {
|
||||
submissionId: string
|
||||
@@ -146,6 +147,9 @@ const criteriaDetails = computed<
|
||||
}),
|
||||
)
|
||||
})
|
||||
// jsonb 不保留键序,直接遍历会把 40 分的「逻辑正确性」排到最后
|
||||
const sortedCriteria = computed(() => sortFlowchartCriteria(criteriaDetails.value))
|
||||
|
||||
const loading = ref(false)
|
||||
const rendering = ref(false)
|
||||
const showLargeImage = ref(false)
|
||||
|
||||
Reference in New Issue
Block a user