diff --git a/src/oj/problem/components/SubmitFlowchart.vue b/src/oj/problem/components/SubmitFlowchart.vue index 78d9e6e..f407dc6 100644 --- a/src/oj/problem/components/SubmitFlowchart.vue +++ b/src/oj/problem/components/SubmitFlowchart.vue @@ -106,7 +106,7 @@ async function submitFlowchartData(flowchartEditorRef: any) { // 获取流程图的JSON数据 const flowchartData = flowchartEditorRef.value.getFlowchartData() - if (flowchartData.nodes.length === 0 || flowchartData.edges.length === 0) { + if (!flowchartData?.nodes?.length || !flowchartData?.edges?.length) { message.error("流程图节点或边不能为空") return } diff --git a/src/oj/problem/composables/useMermaidConverter.ts b/src/oj/problem/composables/useMermaidConverter.ts index 1a0372a..b5641c5 100644 --- a/src/oj/problem/composables/useMermaidConverter.ts +++ b/src/oj/problem/composables/useMermaidConverter.ts @@ -11,9 +11,17 @@ export function useMermaidConverter() { let mermaid = "graph TD\n" + // Build safe ID mapping to prevent Mermaid syntax errors from special characters + const idMap = new Map() + nodes.forEach((node: any, index: number) => { + idMap.set(node.id, `node_${index}`) + }) + const safeId = (id: string) => + idMap.get(id) || id.replace(/[^a-zA-Z0-9_]/g, "_") + // 处理节点 - 根据原始类型和自定义标签 nodes.forEach((node: any) => { - const nodeId = node.id + const nodeId = safeId(node.id) const label = node.data?.customLabel || node.data?.label || "节点" const originalType = node.data?.originalType || node.type @@ -50,8 +58,8 @@ export function useMermaidConverter() { // 处理边 edges.forEach((edge: any) => { - const source = edge.source - const target = edge.target + const source = safeId(edge.source) + const target = safeId(edge.target) const label = edge.label ?? "" if (label && label.trim() !== "") { @@ -77,7 +85,7 @@ export function useMermaidConverter() { // 为节点应用样式 nodes.forEach((node: any) => { - const nodeId = node.id + const nodeId = safeId(node.id) const originalType = node.data?.originalType || node.type switch (originalType) { diff --git a/src/shared/components/FlowchartEditor/index.vue b/src/shared/components/FlowchartEditor/index.vue index 81ccffd..0b7bf60 100644 --- a/src/shared/components/FlowchartEditor/index.vue +++ b/src/shared/components/FlowchartEditor/index.vue @@ -114,7 +114,11 @@ const handleClear = () => { // 键盘事件 const handleKeyDown = (event: KeyboardEvent) => { - if (event.target instanceof HTMLInputElement) return + if ( + event.target instanceof HTMLInputElement || + event.target instanceof HTMLTextAreaElement + ) + return if (event.key === "Delete" || event.key === "Backspace") { deleteSelected() diff --git a/src/shared/components/MermaidEditor.vue b/src/shared/components/MermaidEditor.vue index 36b95a9..6c8b65d 100644 --- a/src/shared/components/MermaidEditor.vue +++ b/src/shared/components/MermaidEditor.vue @@ -22,7 +22,7 @@ const loadMermaid = async () => { mermaid = mermaidModule.default mermaid.initialize({ startOnLoad: false, - securityLevel: "loose", + securityLevel: "strict", theme: "default", }) } @@ -72,12 +72,17 @@ const renderMermaid = async () => { const errorMessage = error?.message || "请检查代码语法" renderSuccess.value = false - mermaidContainer.value.innerHTML = ` -
-

❌ Mermaid语法错误

-

${errorMessage}

-
- ` + const errorDiv = document.createElement("div") + errorDiv.style.cssText = "color: #ff4d4f; padding: 20px; text-align: center; border: 1px dashed #ff4d4f; border-radius: 4px;" + const titleP = document.createElement("p") + titleP.textContent = "Mermaid语法错误" + const detailP = document.createElement("p") + detailP.style.cssText = "font-size: 12px; color: #666;" + detailP.textContent = errorMessage + errorDiv.appendChild(titleP) + errorDiv.appendChild(detailP) + mermaidContainer.value.innerHTML = "" + mermaidContainer.value.appendChild(errorDiv) } } diff --git a/src/shared/composables/useMermaid.ts b/src/shared/composables/useMermaid.ts index 5919800..69d9db7 100644 --- a/src/shared/composables/useMermaid.ts +++ b/src/shared/composables/useMermaid.ts @@ -14,7 +14,7 @@ export function useMermaid() { mermaid = mermaidModule.default mermaid.initialize({ startOnLoad: false, - securityLevel: "loose", + securityLevel: "strict", theme: "default", }) }