From 3fa897bec1d791868cd7e66075c07981aac060c8 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Mon, 19 Oct 2026 22:27:46 +0800 Subject: [PATCH] =?UTF-8?q?revert(=E6=B5=81=E7=A8=8B=E5=9B=BE):=20?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E3=80=8C=E6=98=BE=E7=A4=BA=E6=97=B6=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=AE=A4=E8=80=81=E5=8F=82=E8=80=83=E5=9B=BE=E7=9A=84?= =?UTF-8?q?=E6=A1=86=E3=80=8D=E2=80=94=E2=80=94=E7=BA=BF=E4=B8=8A=2036=20?= =?UTF-8?q?=E5=BC=A0=E5=8F=82=E8=80=83=E5=9B=BE=E5=B7=B2=E7=BB=8F=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E8=BD=AC=E6=88=90=E7=BB=93=E6=9E=84=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit c4306b0 是给手写 Mermaid 的老参考图兜底的;36 张已经在线上逐题转成画布格式(自动转 19 张、 照原图手工画 10 张,重复的比赛题 7 张),回读核对过其余字段没变,线上不再有没标种类的图。 Co-Authored-By: Claude Opus 5.5 --- apps/web/src/shared/composables/useMermaid.ts | 5 +- apps/web/src/utils/legacyFlowchart.ts | 113 ------------------ 2 files changed, 1 insertion(+), 117 deletions(-) delete mode 100644 apps/web/src/utils/legacyFlowchart.ts diff --git a/apps/web/src/shared/composables/useMermaid.ts b/apps/web/src/shared/composables/useMermaid.ts index ddda49a..c7039a0 100644 --- a/apps/web/src/shared/composables/useMermaid.ts +++ b/apps/web/src/shared/composables/useMermaid.ts @@ -6,8 +6,6 @@ * pele 的版本号锁死(不带 ^):项目 2026-10 才开,小版本也在改排版。 */ -import { normalizeLegacyFlowchart } from "utils/legacyFlowchart" - const semanticNodeClasses = [ "startNode", "endNode", @@ -137,8 +135,7 @@ export function useMermaid() { try { // pele/lazy 按图的类型现拉对应的模块,题目里绝大多数是流程图,只拉那一块 const { renderAsync } = await import("pele/lazy") - // 老师手写的老参考图一个框的种类都没标,先按标准符号重排(见 legacyFlowchart.ts) - const { svg } = await renderAsync(normalizeLegacyFlowchart(mermaidCode), { + const { svg } = await renderAsync(mermaidCode, { // 量字宽用页面真实的字体,否则框会比字窄或宽 fontFamily: getComputedStyle(container).fontFamily, // 题目是老师写的、提交是学生写的,图里的链接和外链图片一律不画 diff --git a/apps/web/src/utils/legacyFlowchart.ts b/apps/web/src/utils/legacyFlowchart.ts deleted file mode 100644 index 3e1cc24..0000000 --- a/apps/web/src/utils/legacyFlowchart.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * 老师手写的老参考流程图,显示前按标准符号重排。 - * - * 现在的流程图(学生的画布、出题页的参考图)都由结构树生成,每个框带 `class nX input` 这样的 - * 种类,useMermaid 按种类上标准的形状和颜色。2026-10 之前老师直接手写 Mermaid 的参考图 - * (库里 36 张,全是这种)一个种类都没标:输入写成普通方框 `B[输入n]`、开始写成正圆, - * 显示时只能按框里的字分彩色,和学生图上的标准符号对不上。 - * - * 这里只处理**一个种类都没标**的图(学生的老提交全都标了,不受影响),按写法和字认框: - * 花括号是判断;字是「开始 / 结束」的是起止;以「输入」「输出」「打印」开头(或者直接写着 - * input( / print()的是输入输出框;其余是处理框。认出来就换成标准形状、补上种类。靠字猜的:「a = 输入」会被当成处理框。 - * 数据不动,只改显示。 - */ - -const SEMANTIC_CLASS = - /^\s*class\s+[\w,-]+\s+(startNode|endNode|startEnd|input|output|process|decision|loop)\s*;?\s*$/m - -/** 节点的开口和对应的收口,长的在前(`((` 要先于 `(` 认) */ -const SHAPES: [string, string][] = [ - ["((", "))"], - ["([", "])"], - ["[[", "]]"], - ["[(", ")]"], - ["{{", "}}"], - ["[/", "/]"], - ["[\\", "\\]"], - ["[", "]"], - ["(", ")"], - ["{", "}"], -] - -/** 这些开头的行不是节点:声明、分组、样式 */ -const SKIP_LINE = /^\s*(graph|flowchart|subgraph|end\s*$|class|classDef|style|linkStyle|click|%%)/ - -const START = /^(开始|start)$/i -const END = /^(结束|end)$/i -const INPUT = /^(输入|读入|读取|input)/i -const OUTPUT = /^(输出|打印|显示|print|output)/i - -type Kind = "startNode" | "endNode" | "input" | "output" | "process" | "decision" - -function plain(body: string) { - const text = body.trim() - return text.startsWith('"') && text.endsWith('"') && text.length >= 2 ? text.slice(1, -1) : text -} - -function kindOf(open: string, text: string): Kind { - const word = text.replace(//gi, " ").trim() - if (START.test(word)) return "startNode" - if (END.test(word)) return "endNode" - if (open === "{" || open === "{{") return "decision" - // 有老师直接写代码:「a = float(input())」是读数据 - if (INPUT.test(word) || /\binput\s*\(/.test(word)) return "input" - if (OUTPUT.test(word)) return "output" - return "process" -} - -function shaped(kind: Kind, text: string) { - const label = `"${text.replace(/"/g, "#quot;")}"` - if (kind === "startNode" || kind === "endNode") return `([${label}])` - if (kind === "decision") return `{${label}}` - if (kind === "input" || kind === "output") return `[/${label}/]` - return `[${label}]` -} - -/** 从 start 起找收口,引号里的不算 */ -function closeAt(line: string, start: number, close: string) { - let quoted = false - for (let i = start; i < line.length; i++) { - if (line[i] === '"') quoted = !quoted - else if (!quoted && line.startsWith(close, i)) return i - } - return -1 -} - -function rewriteLine(line: string, kinds: Map) { - let out = "" - let i = 0 - while (i < line.length) { - const id = /^[A-Za-z_][\w-]*/.exec(line.slice(i)) - const prev = i > 0 ? line[i - 1]! : " " - if (!id || /[\w-]/.test(prev)) { - out += line[i] - i++ - continue - } - const after = i + id[0].length - const shape = SHAPES.find(([open]) => line.startsWith(open, after)) - const end = shape ? closeAt(line, after + shape[0].length, shape[1]) : -1 - if (!shape || end < 0) { - out += id[0] - i = after - continue - } - const text = plain(line.slice(after + shape[0].length, end)) - const kind = kindOf(shape[0], text) - kinds.set(id[0], kind) - out += id[0] + shaped(kind, text) - i = end + shape[1].length - } - return out -} - -export function normalizeLegacyFlowchart(code: string) { - if (!/^\s*(graph|flowchart)\b/.test(code) || SEMANTIC_CLASS.test(code) || code.includes(":::")) - return code - const kinds = new Map() - const lines = code - .split("\n") - .map((line) => (SKIP_LINE.test(line) ? line : rewriteLine(line, kinds))) - if (!kinds.size) return code - return [...lines, "", ...[...kinds].map(([id, kind]) => ` class ${id} ${kind}`)].join("\n") -}