feat: 详情弹框内容添加Markdown显示开关

This commit is contained in:
2026-04-24 12:58:09 +08:00
parent 3f5284e067
commit d7b4b48cc7

View File

@@ -3356,16 +3356,22 @@ async function showDetail(id, todoPage = 1, todoFilter = 'all') {
if (item.content) {
html += `<div class="mb-3">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex justify-content-between align-items-center mb-1">
<strong>内容:</strong>
<small class="text-muted"><i class="bi bi-hand-index"></i> 可先选中部分文本,再双击在此处插入</small>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="markdownToggle-${item.id}-content"
onchange="toggleMarkdownDisplay(${item.id}, 'content', '${escapeHtmlAttr(item.content)}')"
${localStorage.getItem('markdownDisplay') === 'true' ? 'checked' : ''}>
<label class="form-check-label small" for="markdownToggle-${item.id}-content">Markdown</label>
</div>
</div>
<div class="border rounded p-3 bg-light markdown-content quick-insert-area"
<div class="border rounded p-3 bg-light quick-insert-area"
id="contentDisplay-${item.id}"
data-field="content"
data-item-id="${item.id}"
ondblclick="showQuickInsert(${item.id}, 'content')"
style="cursor: pointer;">
${renderMarkdown(item.content)}
${localStorage.getItem('markdownDisplay') === 'false' ? `<pre style="white-space: pre-wrap; word-break: break-all;">${escapeHtml(item.content)}</pre>` : renderMarkdown(item.content)}
</div>
</div>`;
}
@@ -3482,16 +3488,22 @@ async function showDetail(id, todoPage = 1, todoFilter = 'all') {
if (item.note) {
html += `<div class="mb-3">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex justify-content-between align-items-center mb-1">
<strong>详情/备注:</strong>
<small class="text-muted"><i class="bi bi-hand-index"></i> 可先选中部分文本,再双击在此处插入</small>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="markdownToggle-${item.id}-note"
onchange="toggleMarkdownDisplay(${item.id}, 'note', '${escapeHtmlAttr(item.note)}')"
${localStorage.getItem('markdownDisplay') === 'true' ? 'checked' : ''}>
<label class="form-check-label small" for="markdownToggle-${item.id}-note">Markdown</label>
</div>
</div>
<div class="border rounded p-3 bg-light markdown-content quick-insert-area"
<div class="border rounded p-3 bg-light quick-insert-area"
id="noteDisplay-${item.id}"
data-field="note"
data-item-id="${item.id}"
ondblclick="showQuickInsert(${item.id}, 'note')"
style="cursor: pointer;">
${renderMarkdown(item.note)}
${localStorage.getItem('markdownDisplay') === 'false' ? `<pre style="white-space: pre-wrap; word-break: break-all;">${escapeHtml(item.note)}</pre>` : renderMarkdown(item.note)}
</div>
</div>`;
}
@@ -4028,6 +4040,36 @@ function escapeHtml(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// 转义HTML属性值用于传递到 onclick 等属性)
function escapeHtmlAttr(str) {
if (!str) return '';
// 先转义HTML然后转义单引号和反斜杠
return escapeHtml(str).replace(/'/g, '\\&#39;').replace(/"/g, '&quot;').replace(/\\n/g, '\\n');
}
// 切换Markdown显示模式
function toggleMarkdownDisplay(itemId, field, rawContent) {
const displayEl = document.getElementById(`${field}Display-${itemId}`);
const isMarkdown = localStorage.getItem('markdownDisplay') !== 'false';
// 切换状态
localStorage.setItem('markdownDisplay', isMarkdown ? 'false' : 'true');
// 更新显示
if (isMarkdown) {
// 当前是Markdown切换到原始文本
displayEl.innerHTML = `<pre style="white-space: pre-wrap; word-break: break-all;">${escapeHtml(rawContent.replace(/\\n/g, '\\n').replace(/'/g, "'"))}</pre>`;
} else {
// 当前是原始文本切换到Markdown
displayEl.innerHTML = renderMarkdown(rawContent.replace(/\\n/g, '\\n').replace(/'/g, "'"));
}
// 同步更新其他开关状态
document.querySelectorAll(`input[id^="markdownToggle-${itemId}"]`).forEach(toggle => {
toggle.checked = localStorage.getItem('markdownDisplay') !== 'false';
});
}
// 简单Markdown渲染支持标题、粗体、斜体、代码、链接、列表
function renderMarkdown(text) {
if (!text) return '';