add large image preview
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2025-12-30 09:30:35 +08:00
parent 04838dd9dd
commit c3c8f6ad4d
3 changed files with 168 additions and 152 deletions

View File

@@ -36,5 +36,4 @@ function handleClick() {
} }
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@@ -1,148 +1,166 @@
<template> <template>
<n-grid v-if="submission" :cols="5" :x-gap="16"> <n-grid v-if="submission" :cols="5" :x-gap="16">
<!-- 左侧流程图预览区域 --> <!-- 左侧流程图预览区域 -->
<n-gi :span="3"> <n-gi :span="showLargeImage ? 5 : 3">
<n-card title="流程图预览"> <n-card title="流程图预览">
<div class="flowchart"> <template #header-extra>
<n-alert v-if="renderError" type="error" title="流程图渲染失败"> <n-button
{{ renderError }} v-if="!renderError && submission?.mermaid_code"
</n-alert> quaternary
<div class="flowchart" v-else ref="mermaidContainer"></div> size="small"
</div> @click="showLargeImage = !showLargeImage"
</n-card> >
</n-gi> <template #icon>
<Icon
<!-- 右侧评分详情区域 --> :icon="
<n-gi :span="2"> showLargeImage ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'
<!-- AI反馈 --> "
<n-card />
v-if="submission.ai_feedback" </template>
size="small" {{ showLargeImage ? "退出大图" : "查看大图" }}
title="AI反馈" </n-button>
style="margin-bottom: 16px" </template>
> <div class="flowchart">
<n-text>{{ submission.ai_feedback }}</n-text> <n-alert v-if="renderError" type="error" title="流程图渲染失败">
</n-card> {{ renderError }}
</n-alert>
<!-- 改进建议 --> <div class="flowchart" v-else ref="mermaidContainer"></div>
<n-card </div>
v-if="submission.ai_suggestions" </n-card>
size="small" </n-gi>
title="改进建议"
style="margin-bottom: 16px" <!-- 右侧评分详情区域 -->
> <n-gi v-if="!showLargeImage" :span="2">
<n-text>{{ submission.ai_suggestions }}</n-text> <!-- AI反馈 -->
</n-card> <n-card
v-if="submission.ai_feedback"
<!-- 详细评分 --> size="small"
<n-card title="AI反馈"
v-if=" style="margin-bottom: 16px"
submission.ai_criteria_details && >
Object.keys(submission.ai_criteria_details).length > 0 <n-text>{{ submission.ai_feedback }}</n-text>
" </n-card>
size="small"
title="详细评分" <!-- 改进建议 -->
> <n-card
<div v-if="submission.ai_suggestions"
v-for="(detail, key) in submission.ai_criteria_details" size="small"
:key="key" title="改进建议"
style="margin-bottom: 12px" style="margin-bottom: 16px"
> >
<!-- 评分项标题和分数 --> <n-text>{{ submission.ai_suggestions }}</n-text>
<n-flex </n-card>
justify="space-between"
align="center" <!-- 详细评分 -->
style="margin-bottom: 4px" <n-card
> v-if="
<n-text strong>{{ key }}</n-text> submission.ai_criteria_details &&
<n-tag Object.keys(submission.ai_criteria_details).length > 0
:type="getPercentType(detail.score / detail.max)" "
size="small" size="small"
round title="详细评分"
> >
{{ detail.score || 0 }}分 / {{ detail.max }}分 <div
</n-tag> v-for="(detail, key) in submission.ai_criteria_details"
</n-flex> :key="key"
<!-- 评分项详细说明 --> style="margin-bottom: 12px"
<n-text v-if="detail.comment" depth="3" style="font-size: 12px"> >
{{ detail.comment }} <!-- 评分项标题和分数 -->
</n-text> <n-flex
</div> justify="space-between"
</n-card> align="center"
</n-gi> style="margin-bottom: 4px"
</n-grid> >
<n-spin v-else :show="loading" class="loading-container"> <n-text strong>{{ key }}</n-text>
</n-spin> <n-tag
</template> :type="getPercentType(detail.score / detail.max)"
size="small"
<script setup lang="ts"> round
import { FlowchartSubmission } from "utils/types" >
import { useMermaid } from "shared/composables/useMermaid" {{ detail.score || 0 }}分 / {{ detail.max }}分
</n-tag>
interface Props { </n-flex>
submissionId: string <!-- 评分项详细说明 -->
} <n-text v-if="detail.comment" depth="3" style="font-size: 12px">
{{ detail.comment }}
const props = defineProps<Props>() </n-text>
const mermaidContainer = useTemplateRef<HTMLElement>("mermaidContainer") </div>
const { renderError, renderFlowchart } = useMermaid() </n-card>
</n-gi>
const submission = ref<FlowchartSubmission | null>(null) </n-grid>
const loading = ref(false) <n-spin v-else :show="loading" class="loading-container"> </n-spin>
const rendering = ref(false) </template>
function getPercentType(percent: number) { <script setup lang="ts">
if (percent >= 0.8) return "primary" import { Icon } from "@iconify/vue"
else if (percent >= 0.6) return "info" import { FlowchartSubmission } from "utils/types"
else if (percent >= 0.4) return "warning" import { useMermaid } from "shared/composables/useMermaid"
return "error"
} interface Props {
submissionId: string
async function loadSubmission() { }
if (!props.submissionId) return
loading.value = true const props = defineProps<Props>()
try { const mermaidContainer = useTemplateRef<HTMLElement>("mermaidContainer")
const { getFlowchartSubmission } = await import("oj/api") const { renderError, renderFlowchart } = useMermaid()
const res = await getFlowchartSubmission(props.submissionId)
submission.value = res.data const submission = ref<FlowchartSubmission | null>(null)
const loading = ref(false)
// 渲染流程图 const rendering = ref(false)
if (submission.value?.mermaid_code) { const showLargeImage = ref(false)
rendering.value = true
await nextTick() function getPercentType(percent: number) {
await renderFlowchart( if (percent >= 0.8) return "primary"
mermaidContainer.value, else if (percent >= 0.6) return "info"
submission.value.mermaid_code, else if (percent >= 0.4) return "warning"
) return "error"
rendering.value = false }
}
} catch (error) { async function loadSubmission() {
console.error("Failed to load submission:", error) if (!props.submissionId) return
} finally { loading.value = true
loading.value = false try {
} const { getFlowchartSubmission } = await import("oj/api")
} const res = await getFlowchartSubmission(props.submissionId)
submission.value = res.data
watch(() => props.submissionId, loadSubmission, { immediate: true })
</script> // 渲染流程图
if (submission.value?.mermaid_code) {
<style scoped> rendering.value = true
.flowchart { await nextTick()
height: 500px; await renderFlowchart(
display: flex; mermaidContainer.value,
justify-content: center; submission.value.mermaid_code,
align-items: center; )
} rendering.value = false
}
/* 确保 SVG 图表占满容器 */ } catch (error) {
:deep(.flowchart > svg) { console.error("Failed to load submission:", error)
height: 100%; } finally {
} loading.value = false
}
.loading-container { }
min-height: 600px;
display: flex; watch(() => props.submissionId, loadSubmission, { immediate: true })
justify-content: center; </script>
align-items: center;
} <style scoped>
</style> .flowchart {
height: 500px;
display: flex;
justify-content: center;
align-items: center;
}
/* 确保 SVG 图表占满容器 */
:deep(.flowchart > svg) {
height: 100%;
}
.loading-container {
min-height: 600px;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -147,8 +147,7 @@ onMounted(init)
:data="submission.info.data" :data="submission.info.data"
/> />
</n-flex> </n-flex>
<n-spin v-else :show="loading" class="loading-container"> <n-spin v-else :show="loading" class="loading-container"> </n-spin>
</n-spin>
</template> </template>
<style scoped> <style scoped>