1 parent
23844ae301
commit
d25b5dbe6d
268 files changed
+3684
-8861
No files matched your search
@@ -42,12 +42,7 @@
|
||||
<!-- 右侧:评分详情区域 -->
|
||||
<n-gi :span="2">
|
||||
<!-- AI反馈 -->
|
||||
<n-card
|
||||
v-if="submission.aiFeedback"
|
||||
size="small"
|
||||
title="AI反馈"
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
<n-card v-if="submission.aiFeedback" size="small" title="AI反馈" style="margin-bottom: 16px">
|
||||
<n-text>{{ submission.aiFeedback }}</n-text>
|
||||
</n-card>
|
||||
|
||||
@@ -59,10 +54,7 @@
|
||||
style="margin-bottom: 16px"
|
||||
>
|
||||
<n-flex vertical :size="6">
|
||||
<n-text
|
||||
v-for="(suggestion, index) in suggestionLines"
|
||||
:key="`${index}-${suggestion}`"
|
||||
>
|
||||
<n-text v-for="(suggestion, index) in suggestionLines" :key="`${index}-${suggestion}`">
|
||||
{{ suggestion }}
|
||||
</n-text>
|
||||
</n-flex>
|
||||
@@ -70,23 +62,11 @@
|
||||
|
||||
<!-- 详细评分 -->
|
||||
<n-card v-if="sortedCriteria.length > 0" size="small" title="详细评分">
|
||||
<div
|
||||
v-for="[key, detail] in sortedCriteria"
|
||||
:key="key"
|
||||
style="margin-bottom: 12px"
|
||||
>
|
||||
<div v-for="[key, detail] in sortedCriteria" :key="key" style="margin-bottom: 12px">
|
||||
<!-- 评分项标题和分数 -->
|
||||
<n-flex
|
||||
justify="space-between"
|
||||
align="center"
|
||||
style="margin-bottom: 4px"
|
||||
>
|
||||
<n-flex justify="space-between" align="center" style="margin-bottom: 4px">
|
||||
<n-text strong>{{ key }}</n-text>
|
||||
<n-tag
|
||||
:type="getPercentType(detail.score / detail.max)"
|
||||
size="small"
|
||||
round
|
||||
>
|
||||
<n-tag :type="getPercentType(detail.score / detail.max)" size="small" round>
|
||||
{{ detail.score || 0 }}分 / {{ detail.max }}分
|
||||
</n-tag>
|
||||
</n-flex>
|
||||
@@ -121,39 +101,35 @@ const submission = ref<FlowchartSubmission | null>(null)
|
||||
* 评分项明细。契约里是 `Record<string, unknown>` —— 内容是 AI 模型原样吐出的 JSON,
|
||||
* 后端不校验形状,所以这里只能按约定断言,字段缺失时用 0 / 空串兜底。
|
||||
*/
|
||||
const criteriaDetails = computed<
|
||||
Record<string, { score: number; max: number; comment: string }>
|
||||
>(() => {
|
||||
const raw = submission.value?.aiCriteriaDetails ?? {}
|
||||
return Object.fromEntries(
|
||||
Object.entries(raw).map(([key, value]) => {
|
||||
const item = (value ?? {}) as Partial<{
|
||||
score: number
|
||||
max: number
|
||||
comment: string
|
||||
}>
|
||||
return [
|
||||
key,
|
||||
{
|
||||
score: item.score ?? 0,
|
||||
max: item.max ?? 0,
|
||||
comment: item.comment ?? "",
|
||||
},
|
||||
]
|
||||
}),
|
||||
)
|
||||
})
|
||||
// jsonb 不保留键序,直接遍历会把 40 分的「逻辑正确性」排到最后
|
||||
const sortedCriteria = computed(() =>
|
||||
sortFlowchartCriteria(criteriaDetails.value),
|
||||
const criteriaDetails = computed<Record<string, { score: number; max: number; comment: string }>>(
|
||||
() => {
|
||||
const raw = submission.value?.aiCriteriaDetails ?? {}
|
||||
return Object.fromEntries(
|
||||
Object.entries(raw).map(([key, value]) => {
|
||||
const item = (value ?? {}) as Partial<{
|
||||
score: number
|
||||
max: number
|
||||
comment: string
|
||||
}>
|
||||
return [
|
||||
key,
|
||||
{
|
||||
score: item.score ?? 0,
|
||||
max: item.max ?? 0,
|
||||
comment: item.comment ?? "",
|
||||
},
|
||||
]
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
// jsonb 不保留键序,直接遍历会把 40 分的「逻辑正确性」排到最后
|
||||
const sortedCriteria = computed(() => sortFlowchartCriteria(criteriaDetails.value))
|
||||
|
||||
const loading = ref(false)
|
||||
const rendering = ref(false)
|
||||
const showLargeImage = ref(false)
|
||||
const suggestionLines = computed(() =>
|
||||
splitSuggestionLines(submission.value?.aiSuggestions),
|
||||
)
|
||||
const suggestionLines = computed(() => splitSuggestionLines(submission.value?.aiSuggestions))
|
||||
|
||||
function splitSuggestionLines(suggestions?: string | null) {
|
||||
return suggestions
|
||||
@@ -184,10 +160,7 @@ async function loadSubmission() {
|
||||
if (submission.value?.mermaidCode) {
|
||||
rendering.value = true
|
||||
await nextTick()
|
||||
await renderFlowchart(
|
||||
mermaidContainer.value,
|
||||
submission.value.mermaidCode,
|
||||
)
|
||||
await renderFlowchart(mermaidContainer.value, submission.value.mermaidCode)
|
||||
rendering.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -42,9 +42,7 @@ const props = defineProps<Props>()
|
||||
defineEmits(["showCode"])
|
||||
|
||||
const userStore = useUserStore()
|
||||
const isOwnSubmission = computed(
|
||||
() => userStore.profile?.user?.id === props.submission.userId,
|
||||
)
|
||||
const isOwnSubmission = computed(() => userStore.profile?.user?.id === props.submission.userId)
|
||||
|
||||
function goto() {
|
||||
window.open("/submission/" + props.submission.id, "_blank")
|
||||
|
||||
@@ -94,9 +94,7 @@ onMounted(async () => {
|
||||
class="hour-bars"
|
||||
:style="{
|
||||
borderBottomColor:
|
||||
hour === currentHour
|
||||
? themeVars.primaryColor
|
||||
: themeVars.dividerColor,
|
||||
hour === currentHour ? themeVars.primaryColor : themeVars.dividerColor,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
@@ -118,9 +116,7 @@ onMounted(async () => {
|
||||
<n-divider style="margin: 16px 0">按语言</n-divider>
|
||||
<div class="rows">
|
||||
<div class="row" v-for="row in stats.languages" :key="row.language">
|
||||
<n-text class="row-name">{{
|
||||
LANGUAGE_SHOW_VALUE[row.language]
|
||||
}}</n-text>
|
||||
<n-text class="row-name">{{ LANGUAGE_SHOW_VALUE[row.language] }}</n-text>
|
||||
<n-progress
|
||||
class="row-bar"
|
||||
type="line"
|
||||
@@ -134,12 +130,7 @@ onMounted(async () => {
|
||||
|
||||
<n-divider style="margin: 16px 0">按状态</n-divider>
|
||||
<n-flex align="center">
|
||||
<n-flex
|
||||
align="center"
|
||||
:size="4"
|
||||
v-for="row in stats.results"
|
||||
:key="row.result"
|
||||
>
|
||||
<n-flex align="center" :size="4" v-for="row in stats.results" :key="row.result">
|
||||
<SubmissionResultTag :result="row.result" />
|
||||
<n-text>{{ row.count }}</n-text>
|
||||
</n-flex>
|
||||
@@ -148,11 +139,7 @@ onMounted(async () => {
|
||||
<template v-if="stats.problems.length">
|
||||
<n-divider style="margin: 16px 0">今天最热的题</n-divider>
|
||||
<div class="rows">
|
||||
<div
|
||||
class="row"
|
||||
v-for="row in stats.problems"
|
||||
:key="row.problemDisplayId"
|
||||
>
|
||||
<div class="row" v-for="row in stats.problems" :key="row.problemDisplayId">
|
||||
<n-button
|
||||
class="problem"
|
||||
text
|
||||
@@ -169,11 +156,7 @@ onMounted(async () => {
|
||||
</template>
|
||||
</template>
|
||||
<!-- 请求失败时 stats 还是 null,转圈停下来总得留句话 -->
|
||||
<n-empty
|
||||
v-else-if="!loading"
|
||||
description="统计拉取失败"
|
||||
style="margin: 40px 0"
|
||||
/>
|
||||
<n-empty v-else-if="!loading" description="统计拉取失败" style="margin: 40px 0" />
|
||||
<div v-else style="height: 200px"></div>
|
||||
</n-spin>
|
||||
</template>
|
||||
|
||||
Reference in new issue
Block a user