'commit'
This commit is contained in:
@@ -164,39 +164,53 @@
|
||||
<script src="js/element-plus.zh-cn.min.js"></script>
|
||||
<script src="js/axios.min.js"></script>
|
||||
<!-- Markdown & LaTeX Support -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/github-markdown-css@5.5.1/github-markdown-dark.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/katex@0.16.9/dist/katex.min.css">
|
||||
<script src="https://unpkg.com/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://unpkg.com/marked@12.0.0/lib/marked.umd.js"></script>
|
||||
<link rel="stylesheet" href="https://gcore.jsdelivr.net/npm/github-markdown-css@5.5.1/github-markdown-dark.css">
|
||||
<link rel="stylesheet" href="https://gcore.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
||||
<script src="https://gcore.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://gcore.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
|
||||
<style>
|
||||
/* 适配对话框中的 Markdown 样式 */
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 15px;
|
||||
background-color: transparent !important;
|
||||
padding: 24px;
|
||||
background-color: #0f172a !important;
|
||||
color: #cbd5e1 !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
/* 深度覆盖:确保列表和加粗在任何情况下都可见 */
|
||||
.markdown-body ul {
|
||||
list-style-type: disc !important;
|
||||
padding-left: 2em !important;
|
||||
margin-top: 0.5em !important;
|
||||
margin-bottom: 0.5em !important;
|
||||
}
|
||||
.markdown-body li {
|
||||
display: list-item !important;
|
||||
margin-bottom: 0.25em !important;
|
||||
}
|
||||
.markdown-body strong {
|
||||
font-weight: bold !important;
|
||||
color: #f1f5f9 !important;
|
||||
}
|
||||
.markdown-body p {
|
||||
margin-bottom: 1em !important;
|
||||
}
|
||||
|
||||
.el-dialog {
|
||||
background-color: #1e293b !important;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.el-dialog__title {
|
||||
color: #f1f5f9 !important;
|
||||
}
|
||||
.el-dialog__body {
|
||||
color: #cbd5e1 !important;
|
||||
}
|
||||
.cursor-blink {
|
||||
color: #3b82f6;
|
||||
font-weight: bold;
|
||||
animation: blink 1s step-end infinite;
|
||||
}
|
||||
@keyframes blink {
|
||||
from, to { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
background-color: #0f172a !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
<script src="js/douyin.js"></script>
|
||||
|
||||
@@ -1,5 +1,75 @@
|
||||
const { createApp, ref, computed, onMounted } = Vue;
|
||||
|
||||
// 1. 全局渲染器 - 纯手写的高鲁棒性解析器,不再依赖 marked
|
||||
const globalRenderMarkdown = (text) => {
|
||||
if (!text) return '';
|
||||
|
||||
// 0. 预处理:去除 AI 可能返回的代码块标记
|
||||
let cleanText = text.trim();
|
||||
// 去除开头的 ```markdown 或 ```
|
||||
cleanText = cleanText.replace(/^```(markdown)?\s*/i, '');
|
||||
// 去除结尾的 ```
|
||||
cleanText = cleanText.replace(/```\s*$/, '');
|
||||
|
||||
// 1. 预处理:按行分割
|
||||
const lines = cleanText.split('\n');
|
||||
let html = '';
|
||||
let inList = false;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
// 关键:去除行首尾空白,解决缩进导致的解析失败
|
||||
let trimmed = line.trim();
|
||||
|
||||
// 空行处理
|
||||
if (!trimmed) {
|
||||
if (inList) { html += '</ul>\n'; inList = false; }
|
||||
continue; // 忽略空行,或者可以加 <br>
|
||||
}
|
||||
|
||||
// 2. 内联格式处理(加粗、代码、链接)
|
||||
// 加粗 **text** -> <strong>text</strong>
|
||||
trimmed = trimmed.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||||
// 代码 `text` -> <code>text</code>
|
||||
trimmed = trimmed.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
|
||||
// 3. 块级元素处理
|
||||
// 标题 ### Title
|
||||
if (trimmed.startsWith('###')) {
|
||||
if (inList) { html += '</ul>\n'; inList = false; }
|
||||
html += `<h3>${trimmed.replace(/^###\s*/, '')}</h3>`;
|
||||
}
|
||||
else if (trimmed.startsWith('##')) {
|
||||
if (inList) { html += '</ul>\n'; inList = false; }
|
||||
html += `<h2>${trimmed.replace(/^##\s*/, '')}</h2>`;
|
||||
}
|
||||
else if (trimmed.startsWith('#')) {
|
||||
if (inList) { html += '</ul>\n'; inList = false; }
|
||||
html += `<h1>${trimmed.replace(/^#\s*/, '')}</h1>`;
|
||||
}
|
||||
// 列表 - Item 或 * Item
|
||||
else if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
|
||||
if (!inList) { html += '<ul>\n'; inList = true; }
|
||||
html += `<li>${trimmed.substring(2)}</li>`;
|
||||
}
|
||||
// 数字列表 1. Item
|
||||
else if (/^\d+\.\s/.test(trimmed)) {
|
||||
// 简单起见,数字列表也用 ul,或者你可以维护一个 ordered list 状态
|
||||
if (!inList) { html += '<ul>\n'; inList = true; }
|
||||
html += `<li>${trimmed.replace(/^\d+\.\s/, '')}</li>`;
|
||||
}
|
||||
// 普通段落
|
||||
else {
|
||||
if (inList) { html += '</ul>\n'; inList = false; }
|
||||
html += `<p>${trimmed}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (inList) { html += '</ul>\n'; }
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
const apiBase = ref(window.location.origin || "http://localhost:8000");
|
||||
@@ -15,96 +85,26 @@ createApp({
|
||||
const summaryLoading = ref(false);
|
||||
const summaryText = ref('');
|
||||
|
||||
// 降级用的简易 Markdown 解析器
|
||||
const simpleMarkdown = (text) => {
|
||||
if (!text) return '';
|
||||
let lines = text.split('\n');
|
||||
let html = '';
|
||||
let inList = false;
|
||||
const parseInline = (str) => {
|
||||
return str
|
||||
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/`(.*?)`/g, '<code style="background:rgba(148, 163, 184, 0.1); padding:2px 4px; border-radius:4px;">$1</code>');
|
||||
};
|
||||
for (let line of lines) {
|
||||
let trimmed = line.trim();
|
||||
if (!trimmed) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += '<br>';
|
||||
continue;
|
||||
}
|
||||
if (trimmed.startsWith('### ')) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<h3>${parseInline(trimmed.substring(4))}</h3>`;
|
||||
} else if (trimmed.startsWith('- ') || /^\d+\./.test(trimmed)) {
|
||||
if (!inList) { html += '<ul>'; inList = true; }
|
||||
let content = trimmed.replace(/^(- |\d+\. )/, '');
|
||||
html += `<li>${parseInline(content)}</li>`;
|
||||
} else {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<p>${parseInline(trimmed)}</p>`;
|
||||
}
|
||||
}
|
||||
if (inList) html += '</ul>';
|
||||
return html;
|
||||
};
|
||||
|
||||
// Configure Marked
|
||||
if (typeof marked !== 'undefined') {
|
||||
marked.use({
|
||||
gfm: true,
|
||||
breaks: true
|
||||
});
|
||||
}
|
||||
|
||||
// 增强的 Markdown & LaTeX 解析器
|
||||
const renderMarkdownAndLatex = (text) => {
|
||||
if (!text) return '';
|
||||
|
||||
try {
|
||||
let processedText = text;
|
||||
|
||||
// 1. 处理 LaTeX
|
||||
if (typeof katex !== 'undefined') {
|
||||
// 处理块级 LaTeX: $$ ... $$
|
||||
processedText = processedText.replace(/\$\$\s*([\s\S]*?)\s*\$\$/g, (match, formula) => {
|
||||
try {
|
||||
return '<div class="katex-block">' + katex.renderToString(formula, { displayMode: true, throwOnError: false }) + '</div>';
|
||||
} catch (e) { return match; }
|
||||
});
|
||||
|
||||
// 处理行内 LaTeX: $ ... $
|
||||
processedText = processedText.replace(/\$([^\$\n]+?)\$/g, (match, formula) => {
|
||||
try {
|
||||
return katex.renderToString(formula, { displayMode: false, throwOnError: false });
|
||||
} catch (e) { return match; }
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 使用 marked 解析 Markdown
|
||||
if (typeof marked !== 'undefined') {
|
||||
// marked v12+ 使用 marked.parse
|
||||
return marked.parse(processedText);
|
||||
} else {
|
||||
// 降级使用 simpleMarkdown
|
||||
return simpleMarkdown(processedText);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Markdown rendering error:', e);
|
||||
// 最后的兜底:如果 marked 报错,尝试用 simpleMarkdown
|
||||
try {
|
||||
return simpleMarkdown(text);
|
||||
} catch (e2) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 使用全局渲染器
|
||||
const renderedSummary = computed(() => {
|
||||
if (!summaryText.value) return '';
|
||||
return renderMarkdownAndLatex(summaryText.value);
|
||||
const html = globalRenderMarkdown(summaryText.value);
|
||||
return html;
|
||||
});
|
||||
|
||||
// 这里的配置仍然保留,作为双重保险
|
||||
if (typeof marked !== 'undefined') {
|
||||
const m = (typeof marked.marked === 'function') ? marked.marked : marked;
|
||||
if (m.setOptions) {
|
||||
m.setOptions({
|
||||
gfm: true,
|
||||
breaks: true,
|
||||
mangle: false,
|
||||
headerIds: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
const startParsing = async () => {
|
||||
if (!shareText.value.trim()) return;
|
||||
|
||||
Reference in New Issue
Block a user