feat: 详情弹框内容支持Markdown格式显示

This commit is contained in:
2026-04-22 12:06:42 +08:00
parent 489e95d677
commit eec8b477be

View File

@@ -1074,6 +1074,16 @@ INDEX_TEMPLATE = '''
.type-todo { border-left: 4px solid #ffc107; }
.is-starred { border-left: 4px solid #ffc107; background: #fffbe6; }
.is-starred:hover { background: #fff9e0; }
/* Markdown内容样式 */
.markdown-content { line-height: 1.6; }
.markdown-content h3 { font-size: 1.2em; margin-bottom: 0.5em; }
.markdown-content h4 { font-size: 1.1em; margin-bottom: 0.4em; }
.markdown-content h5 { font-size: 1.0em; margin-bottom: 0.3em; }
.markdown-content h6 { font-size: 0.9em; margin-bottom: 0.2em; }
.markdown-content code { font-size: 0.9em; }
.markdown-content pre { font-size: 0.85em; overflow-x: auto; }
.markdown-content ul, .markdown-content ol { margin-bottom: 0.5em; }
.markdown-content a { color: #0d6efd; }
.star-btn { font-size: 11px; }
.status-pending { color: #ffc107; }
.status-in_progress { color: #17a2b8; }
@@ -2681,7 +2691,7 @@ async function showDetail(id) {
}
if (item.content) {
html += `<div class="mb-3"><strong>内容:</strong><br><div class="border rounded p-3 bg-light" style="white-space: pre-wrap; word-break: break-all;">${escapeHtml(item.content)}</div></div>`;
html += `<div class="mb-3"><strong>内容:</strong><br><div class="border rounded p-3 bg-light markdown-content">${renderMarkdown(item.content)}</div></div>`;
}
if (item.source) {
@@ -2701,7 +2711,7 @@ async function showDetail(id) {
}
if (item.note) {
html += `<div class="mb-3"><strong>详情/备注:</strong><br><div class="border rounded p-3 bg-light" style="white-space: pre-wrap; word-break: break-all;">${escapeHtml(item.note)}</div></div>`;
html += `<div class="mb-3"><strong>详情/备注:</strong><br><div class="border rounded p-3 bg-light markdown-content">${renderMarkdown(item.note)}</div></div>`;
}
html += `<div class="text-muted small"><strong>创建时间:</strong> ${formatDate(item.created_at)}<br><strong>更新时间:</strong> ${formatDate(item.updated_at)}</div>`;
@@ -3032,6 +3042,55 @@ function escapeHtml(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// 简单Markdown渲染支持标题、粗体、斜体、代码、链接、列表
function renderMarkdown(text) {
if (!text) return '';
// 先转义HTML
let html = escapeHtml(text);
// 代码块 ```code```
html = html.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre class="bg-dark text-light p-2 rounded"><code>$2</code></pre>');
// 行内代码 `code`
html = html.replace(/`([^`]+)`/g, '<code class="bg-light px-1 rounded">$1</code>');
// 标题 # ## ### ####
html = html.replace(/^#### (.+)$/gm, '<h6 class="mt-2">$1</h6>');
html = html.replace(/^### (.+)$/gm, '<h5 class="mt-2">$1</h5>');
html = html.replace(/^## (.+)$/gm, '<h4 class="mt-2">$1</h4>');
html = html.replace(/^# (.+)$/gm, '<h3 class="mt-2">$1</h3>');
// 粗体 **text**
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
// 斜体 *text*
html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
// 链接 [text](url)
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
// 无序列表 - item
html = html.replace(/^- (.+)$/gm, '<li class="ms-3">$1</li>');
html = html.replace(/(<li.*<\/li>\n?)+/g, '<ul class="mb-2">$&</ul>');
// 有序列表 1. item
html = html.replace(/^\d+\. (.+)$/gm, '<li class="ms-3">$1</li>');
// 段落分隔(两个换行)
html = html.replace(/\n\n/g, '</p><p class="mb-2">');
// 单换行
html = html.replace(/\n/g, '<br>');
// 包装在段落中
if (!html.startsWith('<')) {
html = '<p class="mb-2">' + html + '</p>';
}
return html;
}
// 标签管理
let allTags = [];