This commit is contained in:
丹尼尔
2026-03-12 18:42:23 +08:00
parent 66362780a0
commit 8b62c445fc
10 changed files with 4801 additions and 73 deletions

View File

@@ -127,6 +127,11 @@
</div>
<script>
const $ = (id) => document.getElementById(id);
const escapeHtml = (s) => {
if (s == null) return '';
const t = String(s);
return t.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
// 相对路径,由 Node 代理到后端,适配 -p/-b 任意端口
const API_BASE = '';
const KEY_STORAGE = 'wechat_key';
@@ -171,13 +176,16 @@
const isUrl = (s) => typeof s === 'string' && /^https?:\/\//i.test(s.trim());
const isBase64Like = (s) => typeof s === 'string' && /^[A-Za-z0-9+/=\s]+$/.test(s) && s.replace(/\s+/g, '').length > 60;
// 图片:上游通常提供 ImageContentbase64或 Content 为图片链接
// 图片:上游通常提供 ImageContentbase64或 Content 为图片链接;无法解读时保留原样
if (imageContent || (msgType === 3) || (msgType === 0 && imageContent)) {
const src = isUrl(imageContent) ? imageContent :
(imageContent ? ('data:image/png;base64,' + imageContent.replace(/\s+/g, '')) :
(isUrl(rawContent) ? rawContent : ''));
if (src) {
return `<div class="content"><div>${rawContent ? String(rawContent) : ''}</div><img src="${src}" alt="图片消息" /></div>`;
const fallback = escapeHtml(rawContent ? String(rawContent).slice(0, 200) : '[图片无法显示]');
return '<div class="content">' + (rawContent ? '<div>' + escapeHtml(rawContent) + '</div>' : '') +
'<img src="' + src.replace(/"/g, '&quot;') + '" alt="图片消息" onerror="this.style.display=\'none\';var s=this.nextElementSibling;if(s)s.style.display=\'\';" />' +
'<span class="img-fallback small-label" style="display:none">' + fallback + '</span></div>';
}
}
@@ -197,15 +205,16 @@
return `<div class="content"><a href="${safe}" target="_blank" rel="noopener noreferrer">${safe}</a></div>`;
}
// 若内容看起来是图片 base64则按图片渲染
if (isBase64Like(rawContent) && (msgType === 3 || msgType === 0)) {
// 若内容看起来是图片 base64则按图片渲染;无法解读时维持原样
if (isBase64Like(rawContent) && (msgType === 3 || msgType === 0 || !msgType)) {
const src = 'data:image/png;base64,' + String(rawContent).replace(/\s+/g, '');
return `<div class="content"><img src="${src}" alt="图片消息" /></div>`;
const fallback = escapeHtml(String(rawContent).slice(0, 80) + (rawContent.length > 80 ? '…' : ''));
return '<div class="content"><img src="' + src.replace(/"/g, '&quot;') + '" alt="图片消息" onerror="this.style.display=\'none\';var s=this.nextElementSibling;if(s)s.style.display=\'\';" /><span class="img-fallback small-label" style="display:none">' + fallback + '</span></div>';
}
// 兜底为纯文本(含 MsgType 提示)
const text = rawContent ? String(rawContent) : (msgType != null ? `MsgType=${msgType}` : '');
return `<div class="content">${text}</div>`;
const text = rawContent ? String(rawContent) : (msgType != null ? 'MsgType=' + msgType : '');
return '<div class="content">' + escapeHtml(text) + '</div>';
}
async function loadMessages() {
@@ -235,11 +244,13 @@
});
$('message-list').innerHTML = list.length ? list.map(m => {
const isOut = m.direction === 'out';
const fromLabel = isOut ? ('我 → ' + (m.ToUserName || '')) : (m.FromUserName || m.from || m.MsgId || '-').toString().slice(0, 32);
const toDisplay = m.ToDisplayName || m.ToUserName || '';
const fromDisplay = m.FromDisplayName || m.FromUserName || m.from || m.MsgId || '-';
const fromLabel = isOut ? ('我 → ' + toDisplay) : String(fromDisplay).slice(0, 48);
const time = m.CreateTime ? (typeof m.CreateTime === 'number'
? new Date(m.CreateTime * 1000).toLocaleTimeString('zh-CN', { hour12: false })
: m.CreateTime) : '';
const meta = '<div class="meta"><span class="from">' + fromLabel + '</span>' + (time ? '<span class="time">' + time + '</span>' : '') + '</div>';
const meta = '<div class="meta"><span class="from">' + escapeHtml(fromLabel) + '</span>' + (time ? '<span class="time">' + time + '</span>' : '') + '</div>';
const body = renderMessageContent(m);
return '<div class="msg-item' + (isOut ? ' out' : '') + '">' + meta + body + '</div>';
}).join('') : '<p class="small-label">暂无对话。请确保已登录且后端 WS 已连接 GetSyncMsg发送的消息含图片、音视频等也会在此展示。</p>';