|
|
@@ -1,4 +1,4 @@
|
|
|
-{{-- 知识点讲解完整模板 --}}
|
|
|
+{{-- 知识点讲解模板 --}}
|
|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
<head>
|
|
|
@@ -6,17 +6,14 @@
|
|
|
<title>知识点讲解</title>
|
|
|
<link rel="stylesheet" href="/css/katex/katex.min.css">
|
|
|
@include('pdf.partials.kp-explain-styles')
|
|
|
- @include('pdf.partials.katex-scripts')
|
|
|
- <script src="/js/math-render.js"></script>
|
|
|
</head>
|
|
|
<body>
|
|
|
- <div class="kp-explain">
|
|
|
+ <div class="page">
|
|
|
<div class="kp-explain-header">
|
|
|
<div class="kp-explain-title">知识点讲解</div>
|
|
|
- <div class="kp-explain-subtitle">
|
|
|
- 本章节用于梳理本卷涉及的知识点,帮助学生在做题前完成预习/复盘。
|
|
|
- </div>
|
|
|
+ <div class="kp-explain-subtitle">本章节用于梳理本卷涉及的知识点,帮助学生在做题前完成预习/复盘。</div>
|
|
|
</div>
|
|
|
+
|
|
|
@if(empty($knowledgePoints))
|
|
|
<div class="kp-empty">暂无知识点数据</div>
|
|
|
@else
|
|
|
@@ -28,31 +25,10 @@
|
|
|
</div>
|
|
|
<div class="kp-section-body">
|
|
|
@if(!empty($kp['explanation']))
|
|
|
- {{-- 解析 ## 标题分段:## 知识点 和 ## 知识点应用 --}}
|
|
|
- @php
|
|
|
- $explanation = $kp['explanation'];
|
|
|
- // 提取 ## 知识点 部分
|
|
|
- preg_match('/##\s*知识点\s*\n([\s\S]*?)(?=##\s*知识点应用|$)/u', $explanation, $knowledgeMatch);
|
|
|
- $knowledgeContent = isset($knowledgeMatch[1]) ? trim($knowledgeMatch[1]) : '';
|
|
|
-
|
|
|
- // 提取 ## 知识点应用 部分
|
|
|
- preg_match('/##\s*知识点应用\s*\n([\s\S]*)/u', $explanation, $applicationMatch);
|
|
|
- $applicationContent = isset($applicationMatch[1]) ? trim($applicationMatch[1]) : '';
|
|
|
- @endphp
|
|
|
-
|
|
|
- @if(!empty($knowledgeContent))
|
|
|
- <div class="kp-block">
|
|
|
- <div class="kp-block-title"><span class="check">✓</span>知识点</div>
|
|
|
- <div class="kp-markdown-content">{!! \App\Services\MathFormulaProcessor::processFormulas($knowledgeContent) !!}</div>
|
|
|
- </div>
|
|
|
- @endif
|
|
|
-
|
|
|
- @if(!empty($applicationContent))
|
|
|
- <div class="kp-block">
|
|
|
- <div class="kp-block-title"><span class="check">✓</span>知识点应用</div>
|
|
|
- <div class="kp-markdown-content">{!! \App\Services\MathFormulaProcessor::processFormulas($applicationContent) !!}</div>
|
|
|
- </div>
|
|
|
- @endif
|
|
|
+ {{-- 隐藏容器存储原始 Markdown --}}
|
|
|
+ <div class="kp-markdown-source" style="display:none;">{!! $kp['explanation'] !!}</div>
|
|
|
+ {{-- 渲染容器 --}}
|
|
|
+ <div class="kp-markdown-container kp-markdown-content"></div>
|
|
|
@endif
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -60,40 +36,116 @@
|
|
|
</div>
|
|
|
@endif
|
|
|
</div>
|
|
|
+
|
|
|
+ {{-- 引入脚本 --}}
|
|
|
+ <script src="/js/markdown-it.min.js"></script>
|
|
|
+ <script src="/js/katex.min.js"></script>
|
|
|
+
|
|
|
<script>
|
|
|
- // 确保数学公式渲染系统已初始化
|
|
|
- document.addEventListener('DOMContentLoaded', function() {
|
|
|
- // 延迟渲染,确保所有脚本加载完成
|
|
|
- setTimeout(function() {
|
|
|
- // 渲染 kp-markdown-content 中的公式
|
|
|
- document.querySelectorAll('.kp-markdown-content').forEach(function(el) {
|
|
|
- if (typeof window.renderMathElement === 'function' && el.dataset.rendered !== 'true') {
|
|
|
- window.renderMathElement(el);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- // 如果 MathRender 系统可用,使用它
|
|
|
- if (typeof window.MathRender !== 'undefined') {
|
|
|
- // 临时修改 selector 以渲染 kp-markdown-content
|
|
|
- var originalSelector = window.MathRenderConfig.selector;
|
|
|
- window.MathRenderConfig.selector = '.kp-markdown-content';
|
|
|
- window.MathRender.renderAll();
|
|
|
- window.MathRenderConfig.selector = originalSelector;
|
|
|
+ (function() {
|
|
|
+ 'use strict';
|
|
|
+
|
|
|
+ function waitForLibs(callback) {
|
|
|
+ let attempts = 0;
|
|
|
+ const maxAttempts = 50;
|
|
|
+ const interval = setInterval(function() {
|
|
|
+ attempts++;
|
|
|
+ if (typeof window.markdownit === 'function') {
|
|
|
+ clearInterval(interval);
|
|
|
+ callback();
|
|
|
+ } else if (attempts >= maxAttempts) {
|
|
|
+ clearInterval(interval);
|
|
|
+ console.error('[Render] Libraries failed to load after', maxAttempts, 'attempts');
|
|
|
+ console.log('[Render] markdownit:', typeof window.markdownit);
|
|
|
+ callback();
|
|
|
}
|
|
|
-
|
|
|
- // 触发自定义事件,让其他渲染系统也能响应
|
|
|
- document.dispatchEvent(new CustomEvent('math:render'));
|
|
|
}, 100);
|
|
|
-
|
|
|
- // 再次尝试渲染,处理可能的异步加载情况
|
|
|
- setTimeout(function() {
|
|
|
- document.querySelectorAll('.kp-markdown-content').forEach(function(el) {
|
|
|
- if (typeof window.renderMathElement === 'function' && el.dataset.rendered !== 'true') {
|
|
|
- window.renderMathElement(el);
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderMarkdown(md, targetEl) {
|
|
|
+ if (!md) return;
|
|
|
+
|
|
|
+ if (typeof window.markdownit !== 'function') {
|
|
|
+ targetEl.textContent = md;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const mdParser = window.markdownit({
|
|
|
+ html: false,
|
|
|
+ breaks: false,
|
|
|
+ linkify: true,
|
|
|
+ typographer: false
|
|
|
+ });
|
|
|
+
|
|
|
+ let html = mdParser.render(md);
|
|
|
+
|
|
|
+ if (typeof window.katex !== 'undefined') {
|
|
|
+ const katexOptions = {
|
|
|
+ throwOnError: false,
|
|
|
+ displayMode: false
|
|
|
+ };
|
|
|
+
|
|
|
+ function decodeEntities(input) {
|
|
|
+ return input
|
|
|
+ .replace(/>/g, '>')
|
|
|
+ .replace(/</g, '<')
|
|
|
+ .replace(/&/g, '&')
|
|
|
+ .replace(/"/g, '"')
|
|
|
+ .replace(/'/g, "'");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先渲染块级公式 $$...$$
|
|
|
+ html = html.replace(/\$\$([\s\S]*?)\$\$/g, function(_, tex) {
|
|
|
+ try {
|
|
|
+ const cleaned = decodeEntities(tex.trim());
|
|
|
+ return window.katex.renderToString(cleaned, { ...katexOptions, displayMode: true });
|
|
|
+ } catch (e) {
|
|
|
+ return '<span style="color:red">[KaTeX error]</span>';
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 再渲染行内公式 $...$
|
|
|
+ html = html.replace(/\$([^\$\n]+?)\$/g, function(_, tex) {
|
|
|
+ try {
|
|
|
+ const cleaned = decodeEntities(tex.trim());
|
|
|
+ return window.katex.renderToString(cleaned, { ...katexOptions, displayMode: false });
|
|
|
+ } catch (e) {
|
|
|
+ return '<span style="color:red">[KaTeX error]</span>';
|
|
|
}
|
|
|
});
|
|
|
- }, 500);
|
|
|
+ }
|
|
|
+
|
|
|
+ targetEl.innerHTML = html;
|
|
|
+ }
|
|
|
+
|
|
|
+ function renderAll() {
|
|
|
+ const containers = document.querySelectorAll('.kp-markdown-container');
|
|
|
+ containers.forEach((container) => {
|
|
|
+ const sourceEl = container.previousElementSibling;
|
|
|
+ let markdown = '';
|
|
|
+ if (sourceEl && sourceEl.classList.contains('kp-markdown-source')) {
|
|
|
+ markdown = sourceEl.textContent.trim();
|
|
|
+ }
|
|
|
+ if (!markdown) return;
|
|
|
+ renderMarkdown(markdown, container);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (document.readyState === 'loading') {
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {
|
|
|
+ waitForLibs(renderAll);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ waitForLibs(renderAll);
|
|
|
+ }
|
|
|
+
|
|
|
+ document.addEventListener('livewire:initialized', function() {
|
|
|
+ waitForLibs(renderAll);
|
|
|
});
|
|
|
+ document.addEventListener('livewire:navigated', () => setTimeout(function() {
|
|
|
+ waitForLibs(renderAll);
|
|
|
+ }, 100));
|
|
|
+ })();
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|