/* ============================================================ * lib/components/group-chat.js · 仿企业微信电脑端群聊窗 * 用法: * * * JSON:{ group, subtitle, members:[{name,avatar,role}], * msgs:[{name,avatar,type:'text'|'card', text, at:[names], title, sub, tag}], footer } * 消息文本内 @成员名 自动高亮为提及标签。 * 颜色全部来自 tokens.css 的 --chat-* / --brand-*(双主题自适应)。 * ============================================================ */ (function () { function esc(s) { return String(s == null ? '' : s) .replace(/&/g, '&').replace(//g, '>'); } function nl(s) { return esc(s).replace(/\n/g, '
'); } function parse(el) { if (el.dataset.chat) { try { return JSON.parse(el.dataset.chat); } catch (e) { return null; } } if (el.dataset.ref) { var src = document.querySelector(el.dataset.ref); if (src) { try { return JSON.parse(src.textContent); } catch (e) { return null; } } } return null; } // 把文本里的 @成员名 渲染成高亮提及 function mention(text, members) { var s = esc(text); members.forEach(function (m) { var name = esc(m.name); if (!name) return; var re = new RegExp('(@' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')(?![^<]*>)', 'g'); s = s.replace(re, '$1'); }); return s; } function renderMsg(m, members) { var text = ''; if (m.type === 'card') { text = '
' + (m.title ? '
' + esc(m.title) + '
' : '') + (m.sub ? '
' + esc(m.sub) + '
' : '') + (m.tag ? '
' + esc(m.tag) + '
' : '') + '
'; } else { text = '
' + mention(m.text, members) + '
'; } return '
' + '' + esc(m.avatar || (m.name || '?').slice(0, 1)) + '' + '
' + '
' + esc(m.name || '') + '
' + text + '
' + '
'; } function render(el, d) { if (!d) { el.innerHTML = '
数据缺失
'; return; } var members = d.members || []; var memHTML = members.map(function (m) { return '
' + '' + esc(m.avatar || (m.name || '?').slice(0, 1)) + '' + '
' + '
' + esc(m.name || '') + '
' + (m.role ? '
' + esc(m.role) + '
' : '') + '
' + '
'; }).join(''); var msgs = (d.msgs || []).map(function (m) { return renderMsg(m, members); }).join(''); el.innerHTML = '
' + '
' + esc(d.group || '') + (d.subtitle ? '' + esc(d.subtitle) + '' : '') + '
' + '
' + '
' + memHTML + '
' + '
' + msgs + '
' + '
' + (d.footer ? '
' + esc(d.footer) + '
' : '') + '
'; } var GroupChat = function () { return Reflect.construct(HTMLElement, [], GroupChat); }; GroupChat.prototype = Object.create(HTMLElement.prototype); GroupChat.prototype.constructor = GroupChat; GroupChat.prototype.connectedCallback = function () { var self = this; var d = parse(this); if (!d && this.dataset.ref) { setTimeout(function () { render(self, parse(self)); }, 0); } else { render(this, d); } }; if (!customElements.get('group-chat')) { customElements.define('group-chat', GroupChat); } })();