1515 */
1616import mergeWith from 'lodash/mergeWith' ;
1717import { isBrowser } from '@/utils/env' ;
18+ import Logger from '@/Logger' ;
1819
1920const CHART_TYPES = [
2021 'flowchart' ,
@@ -85,7 +86,7 @@ export default class MermaidCodeEngine {
8586 * @param {Object } mermaidOptions - Mermaid 配置选项
8687 * @param {Object } [mermaidOptions.mermaid] - mermaid 实例对象,如果未提供会尝试从 window.mermaid 获取
8788 * @param {Object } [mermaidOptions.mermaidAPI] - mermaidAPI 实例对象,如果未提供会尝试从 window.mermaidAPI 获取
88- * @param {string } [mermaidOptions.theme='default'] - 主题,可选值: 'default', 'dark', 'forest', 'neutral' 等
89+ * @param {string } [mermaidOptions.theme='default'] - 主题,可选值: 'default', 'dark', 'forest', 'neutral' 等
8990 * @param {string } [mermaidOptions.altFontFamily='sans-serif'] - 备用字体
9091 * @param {string } [mermaidOptions.fontFamily='sans-serif'] - 主字体
9192 * @param {string } [mermaidOptions.themeCSS] - 自定义主题 CSS 样式
@@ -151,7 +152,7 @@ export default class MermaidCodeEngine {
151152 }
152153
153154 /**
154- * 转换svg为img,如果出错则直出svg
155+ * 转换 svg 为 img,如果出错则直出 svg
155156 * @param {string } svgCode
156157 * @param {string } graphId
157158 * @returns {string }
@@ -164,7 +165,7 @@ export default class MermaidCodeEngine {
164165 try {
165166 const svgDoc = /** @type {XMLDocument } */ ( domParser . parseFromString ( svgCode , 'image/svg+xml' ) ) ;
166167 const svgDom = /** @type {SVGSVGElement } */ ( /** @type {any } */ ( svgDoc . documentElement ) ) ;
167- // tagName不是svg时,说明存在parse error
168+ // tagName 不是 svg 时,说明存在 parse error
168169 if ( svgDom . tagName . toLowerCase ( ) === 'svg' ) {
169170 svgDom . style . maxWidth = '100%' ;
170171 svgDom . style . height = 'auto' ;
@@ -180,7 +181,7 @@ export default class MermaidCodeEngine {
180181 svgDom . getAttribute ( 'height' ) === '100%' && svgDom . setAttribute ( 'height' , `${ svgBox . height } ` ) ;
181182 // fix end
182183 svgHtml = svgDoc . documentElement . outerHTML ;
183- // 屏蔽转img标签功能,如需要转换为img解除屏蔽即可
184+ // 屏蔽转 img 标签功能,如需要转换为 img 解除屏蔽即可
184185 if ( this . svg2img ) {
185186 const dataUrl = `data:image/svg+xml,${ encodeURIComponent ( svgDoc . documentElement . outerHTML ) } ` ;
186187 svgHtml = `<img class="svg-img" src="${ dataUrl } " alt="${ graphId } " />` ;
@@ -219,8 +220,8 @@ export default class MermaidCodeEngine {
219220 /**
220221 * 如果开启了流式渲染,当前有上次渲染结果时,使用上次渲染结果
221222 * 这里有赌的成分
222- * 流式输出场景,只有最后一个mermaid代码块在流式输出,随着最后一个mermaid流式输出,mermaid的渲染有概率会失败
223- * 这里赌的是只有一个mermaid代码块需要渲染
223+ * 流式输出场景,只有最后一个 mermaid 代码块在流式输出,随着最后一个 mermaid 流式输出,mermaid 的渲染有概率会失败
224+ * 这里赌的是只有一个 mermaid 代码块需要渲染
224225 */
225226 if ( $engine . $cherry . options . engine . global . flowSessionContext && this . lastRenderedCode ) {
226227 return this . lastRenderedCode ;
@@ -249,6 +250,7 @@ export default class MermaidCodeEngine {
249250
250251 asyncRender ( graphId , src , sign , $engine , props ) {
251252 $engine . asyncRenderHandler . add ( graphId ) ;
253+
252254 this . mermaidAPIRefs
253255 . render ( graphId , src , this . mermaidCanvas )
254256 . then ( ( { svg : svgCode } ) => {
@@ -260,10 +262,10 @@ export default class MermaidCodeEngine {
260262 . catch ( ( ) => {
261263 /**
262264 * 如果开启了流式渲染,当前有上次渲染结果时,使用上次渲染结果
263- * 这里有赌的成分, 流式输出场景,只有最后一个mermaid代码块在流式输出,随着最后一个mermaid流式输出,mermaid的渲染有概率会失败
265+ * 这里有赌的成分, 流式输出场景,只有最后一个 mermaid 代码块在流式输出,随着最后一个 mermaid 流式输出,mermaid 的渲染有概率会失败
264266 * 这里赌的是:
265- * 1、只有一个mermaid代码块需要渲染
266- * 2、纯预览模式,且流式输出场景,所有mermaid都正常输出
267+ * 1、只有一个 mermaid 代码块需要渲染
268+ * 2、纯预览模式,且流式输出场景,所有 mermaid 都正常输出
267269 */
268270 if (
269271 $engine . $cherry . options . engine . global . flowSessionContext &&
@@ -278,22 +280,31 @@ export default class MermaidCodeEngine {
278280 this . handleAsyncRenderDone ( graphId , sign , $engine , props , html ) ;
279281 }
280282 } ) ;
283+ Logger . log ( 'Mermaid async render started:' , { graphId, sign } ) ;
281284 if ( this . needReturnLastRenderedCode ) {
282285 return this . lastRenderedCode ;
283286 }
284- // 先渲染源码
287+ Logger . log ( 'Mermaid async render done:' , { graphId, sign } ) ;
288+
289+ // 【关键修改】在流式渲染模式下,不显示代码块,而是显示占位符
290+ if ( $engine . $cherry . options . engine . global . flowSessionContext ) {
291+ return `<div data-sign="${ sign } " data-type="codeBlock" class="mermaid-loading">
292+ <div class="mermaid-placeholder">Mermaid 图表渲染中...</div>
293+ </div>` ;
294+ }
295+
296+ // 非流式模式下,先渲染源码
285297 return props . fallback ( ) ;
286298 }
287-
288299 render ( src , sign , $engine , props = { } ) {
289300 let $sign = sign ;
290301 if ( ! $sign ) {
291302 $sign = Math . round ( Math . random ( ) * 100000000 ) ;
292303 }
293304 this . mountMermaidCanvas ( $engine ) ;
294- // 多实例的情况下相同的内容ID相同会导致mermaid渲染异常
295- // 需要通过添加时间戳使得多次渲染相同内容的图像ID唯一
296- // 图像渲染节流在CodeBlock Hook内部控制
305+ // 多实例的情况下相同的内容 ID 相同会导致 mermaid 渲染异常
306+ // 需要通过添加时间戳使得多次渲染相同内容的图像 ID 唯一
307+ // 图像渲染节流在 CodeBlock Hook 内部控制
297308 const graphId = `mermaid-${ sign } -${ new Date ( ) . getTime ( ) } ` ;
298309 this . svg2img = props . mermaidConfig ?. svg2img ?? false ;
299310 return this . isAsyncRenderVersion ( )
0 commit comments