Showing
1 changed file
with
113 additions
and
6 deletions
| @@ -146,6 +146,78 @@ class HTMLRenderer: | @@ -146,6 +146,78 @@ class HTMLRenderer: | ||
| 146 | self._pdf_font_base64 = "" | 146 | self._pdf_font_base64 = "" |
| 147 | return self._pdf_font_base64 | 147 | return self._pdf_font_base64 |
| 148 | 148 | ||
| 149 | + def _build_script_with_fallback( | ||
| 150 | + self, | ||
| 151 | + inline_code: str, | ||
| 152 | + cdn_url: str, | ||
| 153 | + check_expression: str, | ||
| 154 | + lib_name: str, | ||
| 155 | + is_defer: bool = False | ||
| 156 | + ) -> str: | ||
| 157 | + """ | ||
| 158 | + 构建带有CDN fallback机制的script标签 | ||
| 159 | + | ||
| 160 | + 策略: | ||
| 161 | + 1. 优先嵌入本地库代码 | ||
| 162 | + 2. 添加检测脚本,验证库是否成功加载 | ||
| 163 | + 3. 如果检测失败,动态加载CDN版本作为备用 | ||
| 164 | + | ||
| 165 | + 参数: | ||
| 166 | + inline_code: 本地库的JavaScript代码内容 | ||
| 167 | + cdn_url: CDN备用链接 | ||
| 168 | + check_expression: JavaScript表达式,用于检测库是否加载成功 | ||
| 169 | + lib_name: 库名称(用于日志输出) | ||
| 170 | + is_defer: 是否使用defer属性 | ||
| 171 | + | ||
| 172 | + 返回: | ||
| 173 | + str: 完整的script标签HTML | ||
| 174 | + """ | ||
| 175 | + defer_attr = ' defer' if is_defer else '' | ||
| 176 | + | ||
| 177 | + if inline_code: | ||
| 178 | + # 嵌入本地库代码,并添加fallback检测 | ||
| 179 | + return f""" | ||
| 180 | + <script{defer_attr}> | ||
| 181 | + // {lib_name} - 嵌入式版本 | ||
| 182 | + try {{ | ||
| 183 | + {inline_code} | ||
| 184 | + }} catch (e) {{ | ||
| 185 | + console.error('{lib_name}嵌入式加载失败:', e); | ||
| 186 | + }} | ||
| 187 | + </script> | ||
| 188 | + <script{defer_attr}> | ||
| 189 | + // {lib_name} - CDN Fallback检测 | ||
| 190 | + (function() {{ | ||
| 191 | + var checkLib = function() {{ | ||
| 192 | + if (!({check_expression})) {{ | ||
| 193 | + console.warn('{lib_name}本地版本加载失败,正在从CDN加载备用版本...'); | ||
| 194 | + var script = document.createElement('script'); | ||
| 195 | + script.src = '{cdn_url}'; | ||
| 196 | + script.onerror = function() {{ | ||
| 197 | + console.error('{lib_name} CDN备用加载也失败了'); | ||
| 198 | + }}; | ||
| 199 | + script.onload = function() {{ | ||
| 200 | + console.log('{lib_name} CDN备用版本加载成功'); | ||
| 201 | + }}; | ||
| 202 | + document.head.appendChild(script); | ||
| 203 | + }} | ||
| 204 | + }}; | ||
| 205 | + | ||
| 206 | + // 延迟检测,确保嵌入代码有时间执行 | ||
| 207 | + if (document.readyState === 'loading') {{ | ||
| 208 | + document.addEventListener('DOMContentLoaded', function() {{ | ||
| 209 | + setTimeout(checkLib, 100); | ||
| 210 | + }}); | ||
| 211 | + }} else {{ | ||
| 212 | + setTimeout(checkLib, 100); | ||
| 213 | + }} | ||
| 214 | + }})(); | ||
| 215 | + </script>""".strip() | ||
| 216 | + else: | ||
| 217 | + # 本地文件读取失败,直接使用CDN | ||
| 218 | + logger.warning(f"{lib_name}本地文件未找到或读取失败,将直接使用CDN") | ||
| 219 | + return f' <script{defer_attr} src="{cdn_url}"></script>' | ||
| 220 | + | ||
| 149 | # ====== 公共入口 ====== | 221 | # ====== 公共入口 ====== |
| 150 | 222 | ||
| 151 | def render(self, document_ir: Dict[str, Any]) -> str: | 223 | def render(self, document_ir: Dict[str, Any]) -> str: |
| @@ -252,12 +324,47 @@ class HTMLRenderer: | @@ -252,12 +324,47 @@ class HTMLRenderer: | ||
| 252 | jspdf = self._load_lib("jspdf.umd.min.js") | 324 | jspdf = self._load_lib("jspdf.umd.min.js") |
| 253 | mathjax = self._load_lib("mathjax.js") | 325 | mathjax = self._load_lib("mathjax.js") |
| 254 | 326 | ||
| 255 | - # 如果库文件加载失败,使用CDN备用链接 | ||
| 256 | - chartjs_tag = f"<script>{chartjs}</script>" if chartjs else '<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>' | ||
| 257 | - sankey_tag = f"<script>{chartjs_sankey}</script>" if chartjs_sankey else '<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-sankey@4"></script>' | ||
| 258 | - html2canvas_tag = f"<script>{html2canvas}</script>" if html2canvas else '<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>' | ||
| 259 | - jspdf_tag = f"<script>{jspdf}</script>" if jspdf else '<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>' | ||
| 260 | - mathjax_tag = f"<script defer>{mathjax}</script>" if mathjax else '<script defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>' | 327 | + # 生成嵌入式script标签,并为每个库添加CDN fallback机制 |
| 328 | + # Chart.js - 主要图表库 | ||
| 329 | + chartjs_tag = self._build_script_with_fallback( | ||
| 330 | + inline_code=chartjs, | ||
| 331 | + cdn_url="https://cdn.jsdelivr.net/npm/chart.js", | ||
| 332 | + check_expression="typeof Chart !== 'undefined'", | ||
| 333 | + lib_name="Chart.js" | ||
| 334 | + ) | ||
| 335 | + | ||
| 336 | + # Chart.js Sankey插件 | ||
| 337 | + sankey_tag = self._build_script_with_fallback( | ||
| 338 | + inline_code=chartjs_sankey, | ||
| 339 | + cdn_url="https://cdn.jsdelivr.net/npm/chartjs-chart-sankey@4", | ||
| 340 | + check_expression="typeof Chart !== 'undefined' && Chart.controllers && Chart.controllers.sankey", | ||
| 341 | + lib_name="chartjs-chart-sankey" | ||
| 342 | + ) | ||
| 343 | + | ||
| 344 | + # html2canvas - 用于截图 | ||
| 345 | + html2canvas_tag = self._build_script_with_fallback( | ||
| 346 | + inline_code=html2canvas, | ||
| 347 | + cdn_url="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js", | ||
| 348 | + check_expression="typeof html2canvas !== 'undefined'", | ||
| 349 | + lib_name="html2canvas" | ||
| 350 | + ) | ||
| 351 | + | ||
| 352 | + # jsPDF - 用于PDF导出 | ||
| 353 | + jspdf_tag = self._build_script_with_fallback( | ||
| 354 | + inline_code=jspdf, | ||
| 355 | + cdn_url="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js", | ||
| 356 | + check_expression="typeof jspdf !== 'undefined'", | ||
| 357 | + lib_name="jsPDF" | ||
| 358 | + ) | ||
| 359 | + | ||
| 360 | + # MathJax - 数学公式渲染 | ||
| 361 | + mathjax_tag = self._build_script_with_fallback( | ||
| 362 | + inline_code=mathjax, | ||
| 363 | + cdn_url="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js", | ||
| 364 | + check_expression="typeof MathJax !== 'undefined'", | ||
| 365 | + lib_name="MathJax", | ||
| 366 | + is_defer=True | ||
| 367 | + ) | ||
| 261 | 368 | ||
| 262 | # PDF字体数据不再嵌入HTML,减小文件体积 | 369 | # PDF字体数据不再嵌入HTML,减小文件体积 |
| 263 | pdf_font_script = "" | 370 | pdf_font_script = "" |
-
Please register or login to post a comment