chore: CRM-NEW baseline

This commit is contained in:
wangliang
2026-10-23 10:35:28 +08:00
commit aa499f6dbf
111 changed files with 15126 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
'use strict';
// 极简 Markdown → HTML(只覆盖 LLM 常用:粗体、链接、列表、段落、行内代码)。
// LibreDesk 的 live chat 消息按 HTML 渲染,直接发 Markdown 会显示成 ** 和 [text](url)。
function escapeHtml(text) {
return String(text || '')
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function inline(text) {
const links = [];
let out = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (_, label, url) => {
links.push(`<a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`);
return `\u0000L${links.length - 1}\u0000`;
});
out = out.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
out = out.replace(/`([^`]+)`/g, '<code>$1</code>');
// 裸 URL 自动转链接(占位符里还没有 http,避免重复处理 href)
out = out.replace(/(https?:\/\/[^\s<]+)/g, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
out = out.replace(/\u0000L(\d+)\u0000/g, (_, i) => links[Number(i)] || '');
return out;
}
function markdownToHtml(markdown) {
const escaped = escapeHtml(markdown);
const lines = escaped.split(/\r?\n/);
const html = [];
let paragraph = [];
let list = null; // 'ul' | 'ol'
const flushParagraph = () => {
if (!paragraph.length) return;
html.push(`<p>${paragraph.map(inline).join('<br>')}</p>`);
paragraph = [];
};
const closeList = () => {
if (!list) return;
html.push(`</${list}>`);
list = null;
};
for (const rawLine of lines) {
const line = rawLine.trim();
if (!line) {
flushParagraph();
closeList();
continue;
}
const bullet = /^[-*]\s+(.*)$/.exec(line);
const numbered = /^\d+[.)]\s+(.*)$/.exec(line);
if (bullet || numbered) {
flushParagraph();
const kind = bullet ? 'ul' : 'ol';
if (list !== kind) {
closeList();
list = kind;
html.push(`<${kind}>`);
}
html.push(`<li>${inline((bullet || numbered)[1])}</li>`);
continue;
}
closeList();
const heading = /^#{1,3}\s+(.*)$/.exec(line);
if (heading) {
flushParagraph();
html.push(`<p><strong>${inline(heading[1])}</strong></p>`);
continue;
}
paragraph.push(line);
}
flushParagraph();
closeList();
return html.join('');
}
module.exports = { markdownToHtml, escapeHtml };