自动生成流程图
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2026-01-05 10:22:57 +08:00
parent c3f818e738
commit 9d1896125e
5 changed files with 32 additions and 12 deletions

8
package-lock.json generated
View File

@@ -28,7 +28,7 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"md-editor-v3": "^6.3.0", "md-editor-v3": "^6.3.1",
"mermaid": "^11.12.2", "mermaid": "^11.12.2",
"naive-ui": "^2.43.2", "naive-ui": "^2.43.2",
"nanoid": "^5.1.6", "nanoid": "^5.1.6",
@@ -4530,9 +4530,9 @@
} }
}, },
"node_modules/md-editor-v3": { "node_modules/md-editor-v3": {
"version": "6.3.0", "version": "6.3.1",
"resolved": "https://registry.npmmirror.com/md-editor-v3/-/md-editor-v3-6.3.0.tgz", "resolved": "https://registry.npmjs.org/md-editor-v3/-/md-editor-v3-6.3.1.tgz",
"integrity": "sha512-KvrxFA7YZbrTQ5JH6nTPNnAhfDVAV1uOVUGziyds0+wyCeWL5lbuTXjFmL8/2sILPw2v0VPxCEw7SMTlUQmvzg==", "integrity": "sha512-k9ynxS6Pexs+yNBuuWZ4cDpqvv/zD9p9lbPFGlCqhsCYyFJL7p/mYjUGNH3l8lsQJOUqlgbZe4Kta0ajN030Ug==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.18.7", "@codemirror/autocomplete": "^6.18.7",

View File

@@ -30,7 +30,7 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"md-editor-v3": "^6.3.0", "md-editor-v3": "^6.3.1",
"mermaid": "^11.12.2", "mermaid": "^11.12.2",
"naive-ui": "^2.43.2", "naive-ui": "^2.43.2",
"nanoid": "^5.1.6", "nanoid": "^5.1.6",

View File

@@ -68,6 +68,10 @@ export function toggleProblemVisible(problemID: number) {
return http.put("admin/problem/visible", { id: problemID }) return http.put("admin/problem/visible", { id: problemID })
} }
export function generateFlowchartFromPythonCode(python: string) {
return http.post("admin/problem/flowchart", { python })
}
export function editContestProblem(problem: AdminProblem | BlankProblem) { export function editContestProblem(problem: AdminProblem | BlankProblem) {
return http.put("admin/contest/problem", problem) return http.put("admin/contest/problem", problem)
} }

View File

@@ -14,6 +14,7 @@ import {
createProblem, createProblem,
editContestProblem, editContestProblem,
editProblem, editProblem,
generateFlowchartFromPythonCode,
getProblem, getProblem,
uploadTestcases, uploadTestcases,
} from "../api" } from "../api"
@@ -46,6 +47,8 @@ const title = computed(
})[<string>route.name], })[<string>route.name],
) )
const isAIGenerating = ref(false)
const problem = useLocalStorage<BlankProblem>(STORAGE_KEY.ADMIN_PROBLEM, { const problem = useLocalStorage<BlankProblem>(STORAGE_KEY.ADMIN_PROBLEM, {
_id: "", _id: "",
title: "", title: "",
@@ -405,8 +408,14 @@ function clear() {
location.reload() location.reload()
} }
function generateMermaid() { async function generateMermaid() {
message.info("还在开发中,敬请期待!") isAIGenerating.value = true
const res = await generateFlowchartFromPythonCode(
problem.value.answers.filter((a) => a.language === "Python3")[0].code,
)
isAIGenerating.value = false
message.warning("如果渲染不成功,请复制到外部 AI 网站检查语法")
problem.value.mermaid_code = res.data.flowchart
} }
onMounted(() => { onMounted(() => {
@@ -630,11 +639,15 @@ watch(
<!-- 流程图相关设置 --> <!-- 流程图相关设置 -->
<n-form inline label-placement="left" :show-feedback="false"> <n-form inline label-placement="left" :show-feedback="false">
<n-form-item label="根据上面的答案智能生成 Mermaid 代码"> <n-form-item label="根据上面的【Python答案智能生成 Mermaid 代码">
<n-button <n-button
type="primary" type="primary"
size="small" size="small"
:disabled="!problem.answers.filter((a) => a.code).length" :disabled="
!problem.answers.filter((a) => a.language === 'Python3')[0].code
.length
"
:loading="isAIGenerating"
@click="generateMermaid" @click="generateMermaid"
> >
AI 生成 AI 生成

View File

@@ -295,9 +295,15 @@ watch(() => [query.page, query.limit, query.type, query.orderBy], listUsers)
<n-form-item-gi :span="1" label="真名"> <n-form-item-gi :span="1" label="真名">
<n-input v-model:value="userEditing.real_name" /> <n-input v-model:value="userEditing.real_name" />
</n-form-item-gi> </n-form-item-gi>
<n-form-item-gi v-if="!create" :span="1" label="班级">
<n-input v-model:value="userEditing.class_name" />
</n-form-item-gi>
<n-form-item-gi :span="1" label="邮箱"> <n-form-item-gi :span="1" label="邮箱">
<n-input v-model:value="userEditing.email" /> <n-input v-model:value="userEditing.email" />
</n-form-item-gi> </n-form-item-gi>
<n-form-item-gi v-if="!create" :span="1" label="类型">
<n-select v-model:value="userEditing.admin_type" :options="options" />
</n-form-item-gi>
<n-form-item-gi <n-form-item-gi
:span="1" :span="1"
label="密码" label="密码"
@@ -305,9 +311,6 @@ watch(() => [query.page, query.limit, query.type, query.orderBy], listUsers)
> >
<n-input v-model:value="password" /> <n-input v-model:value="password" />
</n-form-item-gi> </n-form-item-gi>
<n-form-item-gi v-if="!create" :span="1" label="类型">
<n-select v-model:value="userEditing.admin_type" :options="options" />
</n-form-item-gi>
<n-form-item-gi <n-form-item-gi
v-if="!create && userEditing.admin_type === USER_TYPE.ADMIN" v-if="!create && userEditing.admin_type === USER_TYPE.ADMIN"
:span="1" :span="1"